2011-12-16 52 views
1

鑑於反直觀的行爲虛函數

#include <string> 
#include <iostream> 


struct A { 
    virtual operator std::string() const { return "A"; } 
    virtual operator const char *() const { return this->operator std::string().c_str(); } 
}; 

struct B1 : public A { 
    virtual operator std::string() const { return "<"; } 
}; 

struct B2 { 
    B2() { } 
    virtual ~B2() { } 
    virtual operator std::string() const { return ">"; } 
    virtual operator const char *() const { return this->operator std::string().c_str(); } 
}; 

struct C1 : public A { 
    C1() { } 
    virtual ~C1() { } 
    virtual operator std::string() const { return "["; } 
}; 

struct C2 { 
    C2() { } 
    virtual ~C2() { } 
    virtual operator std::string() const { return "]"; } 
    virtual operator const char *() const { return this->operator std::string().c_str(); } 
}; 

int main() { 
    using namespace std; 
    cout << B1() << endl; 
    cout << C1(); 
    cout << C2() << B2() << endl; 
} 

輸出應爲 「< []>」。但是,它是「< []]」。

  1. 我錯了嗎?如果是這樣,爲什麼?
  2. 如果不是,那麼這種行爲的潛在原因是什麼?
+0

不要以爲我見過虛擬應用於操作符之前。我很好奇你將如何調用它。 – 2011-12-16 15:01:32

回答

5

其實,你的代碼的行爲是未定義由於以下:

return this->operator std::string().c_str(); 

你調用一個臨時c_str(),後來使用的結果。

你所看到的是未定義行爲的有效表現。現在

,如果你好奇,什麼是真正的引擎蓋下發生的,你可以修改的main()最後一行寫着:

cout << (const void*)C2() << ' ' << (const void*)B2() << endl; 

如果你這樣做,你可能會看到相同的地址打印兩次(在兩種情況下都是懸掛指針)。這是我的電腦上發生的事情,我懷疑你的情況會怎樣。 當然,由於行爲是不確定的,這只是許多可能的表現。

+0

我使用c_str()hack的唯一原因是因爲C++ 11 iostream不起作用,並且拒絕投射到右值。看起來我的解決方法將是shared_ptr 。 – moshbear 2011-12-16 11:22:26

3

你的問題真的可以歸結爲:

#include <string> 
#include <iostream> 

struct B2 { 
    B2() { } 
    virtual ~B2() { } 
    virtual operator std::string() const { return ">"; } 
    virtual operator const char *() const { return this->operator std::string().c_str(); } 
}; 

struct C2 { 
    C2() { } 
    virtual ~C2() { } 
    virtual operator std::string() const { return "]"; } 
    virtual operator const char *() const { return this->operator std::string().c_str(); } 
}; 

int main() { 
    using namespace std; 
    cout << C2() << B2() << endl; 
} 

在哪裏,很明顯,這已經無關,與虛函數。這裏發生的是operator const char*被調用,其調用operator std::string,它返回std::string的臨時值,從中返回.c_str()。由於operator const char*這個暫時的std::string被破壞後,你有一個const char*指向已釋放的內存。

現在任何事情都可能發生,因爲這是UB ...