天天看點

談談explicit關鍵字

今天看到公司的代碼内有大量的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~