有在這裏打球兩個相互作用的特點:
- 賦值運算符永遠不會繼承
- 構造函數是不明確的,或者轉換操作符(
operator T()
)定義用戶轉換,可用於隱式地爲轉換序列的一部分
Assignement算從不繼承
一個簡單的代碼例如:
struct Base {}; // implicitly declares operator=(Base const&);
struct Derived: Base {}; // implicitly declares operator=(Derived const&);
int main() {
Derived d;
Base b;
d = b; // fails
}
從ideone:
prog.cpp: In function ‘int main()’:
prog.cpp:7: error: no match for ‘operator=’ in ‘d = b’
prog.cpp:2: note: candidates are: Derived& Derived::operator=(const Derived&)
轉換序列
每當有一個 「阻抗」 錯配,如這裏:
Derived::operator=
需要一個
- 一個
Base&
提供
Derived const&
參數,編譯器將嘗試建立一個轉換序列,以縮小差距。這種轉換序列可能包含在大多數一個用戶定義的轉換。
在這裏,它會尋找:
- 可以與
Base&
(不明確)被調用的Derived
任何構造
- 在
Base
轉換操作符,將產生一個Derived
項目
沒有Base::operator Derived()
,但有一個Derived::Derived(Base const&)
構造函數。
因此我們的轉換序列爲我們定義:
Base&
Base const&
(簡單)
Derived
(使用Derived::Derived(Base const&)
)
Derived const&
(綁定到const引用臨時對象)
A然後調用Derived::operator(Derived const&)
。
在行動
如果我們增加了一些更多的痕跡,我們可以see it in action的代碼。
#include <iostream>
struct Base {}; // implicitly declares Base& operator(Base const&);
struct Derived: Base {
Derived() {}
Derived(Base const&) { std::cout << "Derived::Derived(Base const&)\n"; }
Derived& operator=(Derived const&) {
std::cout << "Derived::operator=(Derived const&)\n";
return *this;
}
};
int main() {
Derived d;
Base b;
d = b;
}
,輸出:
Derived::Derived(Base const&)
Derived::operator=(Derived const&)
注意:防止出現這種情況?
在C++中,可能會刪除一個用於轉換序列的構造函數。爲此,需要使用explicit
關鍵字在構造函數的聲明前綴。
在C++ 0x中,也可以在轉換運算符(operator T()
)上使用此關鍵字。
如果這裏我們在Derived::Derived(Base const&)
之前使用explicit
那麼代碼就會變形,應該被編譯器拒絕。
也許增加一個複製賦值操作符和一個記錄語句。 ;) – Xeo 2011-05-28 17:38:46
您選擇的答案忘了提及這一點,因爲您定義了Derived(const Base&)構造函數,並且您正在做一個downcast ...如果您沒有定義這個construtor,那麼在嘗試完成作業時會收到編譯錯誤正如我的回答所述。 – Hazok 2011-05-28 17:59:03
@Zach:OP是她挑選的人,不用擔心她已收到所有答案的通知(並且會繼續收到通知)。如果你的答案很好,無論如何都會得到認真的讀者的支持,並且很快會加入最佳答案,並且對將來(不太小心)的讀者也是可見的:) – 2011-05-28 18:08:31