今天看到公司的代碼內有大量的explicit關鍵字,但是老版的MSDN內例子並不完善,實在是不明白,最終從網上一篇文章內找到了答案:原來explicit是為了防止隱式使用拷貝建構函式的.以下附上從新版MSDN中找到的例子和網上那篇文章:
// Copy From MSDN
This keyword is a declaration specifier that can only be applied to in-class constructor declarations. An explicit constructor cannot take part in implicit conversions. It can only be used to explicitly construct an object.
The following program will fail to compile because of the explicit keyword. To resolve the error, remove the explicit keywords and adjust the code in g.
// spec1_explicit.cpp// compile with: /EHsc#include class C {public: int i; explicit C(const C&) // an explicit copy constructor { printf("/nin the copy constructor"); } explicit C(int i ) // an explicit constructor { printf("/nin the constructor"); } C() { i = 0; }};class C2{public: int i; explicit C2(int i ) // an explicit constructor { }};C f(C c){ // C2558 c.i = 2; return c; // first call to copy constructor}void f2(C2){}void g(int i){ f2(i); // C2558 // try the following line instead // f2(C2(i));}int main(){ C c, d; d = f(c); // c is copied}
Note explicit on a constructor with multiple arguments has no effect, since such constructors cannot take part in implicit conversions. However, for the purpose of implicit conversion, explicit will have an effect if a constructor has multiple arguments and all but one of the arguments has a default value.
// Copy From Internet Article
Pointer不看書不知道自己的C++有多差T_T,看到 explicit 時遇到一個問題。請看下面一段程式:
class A{
public:
A(int i) : m_i(i){}
int m_i;
};
int main(){
A a = 0;
a = 10; // 這裡是什麼操作?
}
這個操作產生了一個臨時對象。
我懷疑是預設賦值運算子 “A &operator = (int i){}”,於是重載了一下該運算子,結果確實運行到重載的運算子函數裡了,那麼臨時對象又是如何產生的呢?
難道預設的賦值運算子是這樣操作的?
A &operator = (int i){
A a(i);
return a;
}
這讓我想起了類似的函數操作:
void fn(A a){
// ...
}
這裡可以直接寫fn(10);也是產生了一個臨時對象。
難道真的是這樣嗎?忘解惑。
alexeyomux老兄你用的是哪個編譯器?在我印象之中,好像標準C++並不會給出operator =啊。等我去試一試。
gongminmin當然會有預設的operator=了
按照c++標準,編譯器會產生五個預設成員函數:
預設建構函式
拷貝建構函式
解構函式
operator=
operator&
千裡馬肝class A
{
public:
A(int i) : m_i(i){}
int m_i;
};
分別說說吧:
1. A a = 0;
首先, compiler認為這樣寫是不符合規矩的, 因為A = A才是正常行為。
但是她並不放棄, 通過搜尋, 發現A可以根據一個int構造, 同時這個A(int i)沒有用explicit修飾過。
那麼A a = 0; 這樣的一句話隨即轉變成:
A tmp(0);
A a = tmp;
需要說明的是, A a = tmp是調用的copy ctor, 雖然class A中並沒有, 但是通常不寫copy ctor的話,
compiler都會產生一個memberwise assignment操作性質的ctor, 底層實現通常會以memcpy進行。
2. a = 10;
首先, 這樣同ctor的情況一樣, compiler無法直接進行操作。
類推, 等同於代碼:
A tmp(10);
a = tmp;
需要注意的是, a = tmp是調用的assignment操作, 同ctor一樣,我們自己不寫, 編譯器同樣進行
memberwise assignment操作。
3. fn(A a)
同樣, fn(10)也是不對的, 但是"按照慣例", 呵呵, 會有:
A tmp(10);
fn(tmp);
另外, 為你解惑:
copy ctor的寫法只能是T::T(const T &);
而assignment的寫法可以多變, 即任意. 以T為例,
可以有
T &operator = (int n);
也可有
T &operator = (const char *);
當然, 你要確認如此的定義是對T而言有意義.
然後, 上述a = tmp, 即調用的預設的、標準的、自動產生的T &operator = (const T &).
開銷是會有一個臨時的A tmp產生, 然後memcpy.
但如果你自已寫了T &operator = (int n), 那麼a = 10即意味著a.m_i = 10.
當然, 以開銷而言要視你的T &operator = (int n)是否為inline了.
對於explicit, 當修飾explicit A(int i) : m_i(i){}, 那麼即告訴compiler不要在私底下做那麼多的轉換動作.
而且自動產生如A tmp(0)這樣的東西是我們不想要的, 因為某些情況下自動轉換這種行為是錯誤的.
最後, 相關此類問題, 還有一個話題, 即class A可以有operator int(), 會在
fn(int n){}
A a(3);
fn(a)
起到魔術般的作用. 關於這個, 留給你自己看看書吧:)
最後,祝學習C++的路上一帆風順。Good luck~