2010-07-14 69 views
8
#include <iostream> 

class A { 
    public: 
    A(){ cerr << "A Constructor" << endl; } 
    ~A(){ cerr << "A Destructor" << endl; } 
    A(const A &o){ cerr << "A Copy" << endl; } 
    A& operator=(const A &o){ cerr << "A Assignment" << endl; return *this; } 
}; 


class B : public A { 
    public: 
    B() : A() { cerr << "B Constructor" << endl; } 
    ~B(){ cerr << "B Destructor" << endl; } 
    private: 
    B(const B &o) : A() { cerr << "B Copy" << endl; } 
    B& operator=(const B &o){ cerr << "B Assignment" << endl; return *this; } 
}; 

int main() { 
    A a; 
    const A &b = B(); 
    return 0; 
} 

在GCC 4.2,我得到這個消息:意外const引用行爲

In function 'int main()': 
Line 16: error: 'B::B(const B&)' is private 
compilation terminated due to -Wfatal-errors. 

如果我刪除了 「私人」 從B,我得到的輸出我想到:

A Constructor 
A Constructor 
B Constructor 
B Destructor 
A Destructor 
A Destructor 

我的問題是:爲什麼要製作一個不被稱爲private的方法,無論這個代碼是否編譯?這是標準授權嗎?有沒有解決方法?

+0

我不明白爲什麼這不應該編譯。 FWIW,Comeau與我同意。 – sbi 2010-07-14 18:22:34

+1

@sbi:奇怪的是,Comeau拒絕禁用C++ 0x擴展的代碼,但接受啓用了C++ 0x擴展的代碼。 – 2010-07-14 18:23:26

+0

g ++ 4.4.2,FWIW沒有錯誤。 – 2010-07-14 18:44:20

回答

4

當前標準(C++ 03)中的重要語言似乎在§8.5.3中,它解釋瞭如何初始化引用(In這些引號T1是正在初始化的引用的類型,T2是初始化表達式的類型)。

如果初始化表達式是一個rvalue,與T2類類型,和「cv1 T1」是參考兼容「cv2 T2」的引用在下列方式中的一種(結合的選擇是實現定義):

- 引用綁定到由右值(參見3.10)表示的對象或該對象內的子對象。

- 創建了一個類型爲「cv1 T2」的臨時文件[sic],並調用構造函數將整個右值對象複製到臨時文件中。引用綁定到臨時對象或臨時對象內的子對象。

無論副本是否實際完成,用於生成副本的構造函數都應該可調用。

因此,即使實現將引用直接綁定到臨時對象,複製構造函數也必須是可訪問的。

請注意,根據CWG defect 391的分辨率,這在C++ 0x中發生了變化。新的語言讀取(N3092§8.5.3):

否則,如果T2是一個類類型和

- 初始化表達式是一個右值和「cv1 T1」與「cv2 T2參考兼容「

- T1不引用相關於T2和初始化表達式可以隱式轉換到類型的右值」 cv3 T3"(這種轉換通過枚舉適用轉換函數(13.3.1.6選擇的)和選擇最好的一個通過overl oad resolution(13.3)),

然後,引用在第一種情況下綁定到初始化表達式rvalue,並在第二種情況下綁定到作爲轉換結果的對象(或者在任一情況下,對象的基類子對象)。

第一種情況適用,並且引用「直接綁定」到初始化表達式。

+0

決議記錄/標準討論子對象。顯然子對象有多態性,這讓我有點困惑。出於好奇,標準是否在談論縮小某處?我在2005年的工作副本中找不到任何東西,但我想我只是不知道要搜索什麼。我正在看'標準轉換'和複製構造函數部分。 – 2010-07-14 20:15:16

+0

@Zachary:C++標準的一個「特徵」是主題通常分佈在六個不同的部分,如果您不熟悉可能的情況,就很難在其中找到信息。在這種情況下,Declarator Initializers(§8.5)中的子條款非常重要,因爲您正在初始化引用。關於臨時對象的§12.2很重要,因爲你有一個臨時的類型對象。通常,重要的部分是在一段中間的單個短句。有時我發現它有助於搜索關鍵詞(例如,「參考」)。 – 2010-07-14 21:21:25

1

我覺得這確實是一個編譯器bug,gcc似乎認爲是複製初始化。改用直接初始化:

const A& b(B()); 

在拷貝初始化拷貝構造函數調用總是優化掉(複製省略的一個實例),然後沒有可用。