天天看點

C++中explict聲明構造函數的作用

在 C++ 中, 如果一個類有隻有一個參數的構造函數,C++ 允許一種特殊的聲明類變量的方式。在這種情況下,可以直接将一個對應于構造函數參數類型的資料直接指派給類變量,編譯器在編譯時會自動進行類型轉換,将對應于構造函數參數類型的資料轉換為類的對象。 如果在構造函數前加上 explicit 修飾詞,

則會禁止這種自動轉換,在這種情況下, 即使将對應于構造函數參數類型的資料直接指派給類變量,編譯器也會報錯。

下面以具體執行個體來說明。

建立people.cpp 檔案,然後輸入下列内容:

/*人類,是人的類,不是人類 -:) */

class People

{

public:

int age;

explicit People (int a)

age=a;

}

};

/*三種方式來 “造人” */

void foo ( void )

People p1(10); //方式一

People* p_p2=new People(10); //方式二

People p3=10; //方式三

這段 C++ 程式定義了一個類 people ,包含一個構造函數, 這個構造函數隻包含一個整形參數 a ,可用于在構造類時初始化 age 變量。

然後定義了一個函數foo,在這個函數中我們用三種方式分别建立了三個10歲的“人”。 第一種是最一般的類變量聲明方式。第二種方式其實是聲明了一個people類的指針變量,然後在堆中動态建立了一個people執行個體,并把這個執行個體的位址指派給了p_p2。第三種方式就是我們所說的特殊方式,為什麼說特殊呢?

我們都知道,C/C++是一種強類型語言,不同的資料類型是不能随意轉換的,如果要進行類型轉換,必須進行顯式強制類型轉換,而這裡,沒有進行任何顯式的轉換,直接将一個整型資料指派給了類變量p3。 

是以,可以說,這裡進行了一次隐式類型轉換,編譯器自動将對應于構造函數參數類型的資料轉換為了該類的對象,是以方式三經編譯器自動轉換後和方式一最終的實作方式是一樣的。

不相信? 耳聽為虛,眼見為實,讓我們看看底層的實作方式。

為了更容易比較方式一和方式三的實作方式,我們對上面的代碼作一點修改,去除方式二:

去除方式二的原因是方式二是在堆上動态建立類執行個體,是以會有一些額外代碼影響分析。修改完成後,用下列指令編譯 people.cpp

$ gcc -S people.cpp

"-S"選項是GCC輸出彙編代碼。指令執行後,預設生成people.s。 關鍵部分内容如下:

.globl _Z3foov

.type _Z3foov, @function

_Z3foov:

.LFB5:

pushl %ebp

.LCFI2:

movl %esp, %ebp

.LCFI3:

subl $24, %esp

.LCFI4:

movl $10, 4(%esp)

leal -4(%ebp), %eax

movl %eax, (%esp)

call _ZN6PeopleC1Ei

leal -8(%ebp), %eax

leave

ret

看“.LCFI4” 行後面的東西,1-4行和5-8行幾乎一模一樣,1-4行即為方式一的彙編代碼,5-8即為方式三的彙編代碼。 細心的你可能發現2和6行有所不同,一個是 -4(%ebp) 而另一個一個是 -8(%ebp) ,這分别為類變量P1和P3的位址。

對于不可随意進行類型轉換的強類型語言C/C++來說, 這可以說是C++的一個特性。哦,今天好像不是要說C++的特性,而是要知道explicit關鍵字的作用?

explicit關鍵字到底是什麼作用呢? 它的作用就是禁止這個特性。如文章一開始而言,凡是用explicit關鍵字修飾的構造函數,編譯時就不會進行自動轉換,而會報錯。

讓我們看看吧! 修改代碼:

然後再編譯:

編譯器立馬報錯:

people.cpp: In function ‘void foo()’:

people.cpp:23: 錯誤:請求從 ‘int’ 轉換到非标量類型 ‘People’

繼續閱讀