1、問題
在C++中,編譯器會爲空類提供哪些默認成員函數?分別有什麼樣的功能呢? html
2、詳解
一、空類,聲明時編譯器不會生成任何成員函數
對於空類,編譯器不會生成任何的成員函數,只會生成1個字節的佔位符。ios
有時可能會覺得編譯器會爲空類生成默認構造函數等,事實上是不會的,編譯器只會在須要的時候生成6個成員函數:一個缺省的構造函數、一個拷貝構造函數、一個析構函數、一個賦值運算符、一對取址運算符和一個this指針。函數
代碼:this
- #include <iostream>
- using namespace std;
-
- class Empty_one
- {
- };
- class Empty_two
- {};
- class Empty_three
- {
- virtual void fun() = 0;
- };
- class Empty_four : public Empty_two, public Empty_three
- {
- };
-
- int main()
- {
- cout<<"sizeof(Empty_one):"<<sizeof(Empty_one)<<endl;
- cout<<"sizeof(Empty_two):"<<sizeof(Empty_two)<<endl;
- cout<<"sizeof(Empty_three):"<<sizeof(Empty_three)<<endl;
- cout<<"sizeof(Empty_four):"<<sizeof(Empty_four)<<endl;
- return 0;
- }
運行結果:spa

分析:.net
類Empty_one、Empty_two是空類,但空類一樣能夠被實例化,而每一個實例在內存中都有一個獨一無二的地址,爲了達到這個目的,編譯器每每會給一個空類隱含的加一個字節,這樣空類在實例化後在內存獲得了獨一無二的地址,因此sizeof(Empty_one)和sizeof(Empty_two)的大小爲1。指針
類Empty_three裏面因有一個純虛函數,故有一個指向虛函數的指針(vptr),64位系統分配給指針的大小爲8個字節,因此sizeof(Empty_three)的大小爲8。
code
類Empty_four繼承於Empty_two和Empty_three,編譯器取消Empty_two的佔位符,保留一虛函數表,故大小爲8。xml
二、空類,定義時會生成6個成員函數
當空類Empty_one定義一個對象時Empty_one pt;sizeof(pt)還是爲1,但編譯器會生成6個成員函數:一個缺省的構造函數、一個拷貝構造函數、一個析構函數、一個賦值運算符、兩個取址運算符。htm
等價於:
- class Empty
- {
- public:
- Empty(); //缺省構造函數
- Empty(const Empty &rhs); //拷貝構造函數
- ~Empty(); //析構函數
- Empty& operator=(const Empty &rhs); //賦值運算符
- Empty* operator&(); //取址運算符
- const Empty* operator&() const; //取址運算符(const版本)
- };
使用時的調用狀況:
- Empty *e = new Empty(); //缺省構造函數
- delete e; //析構函數
- Empty e1; //缺省構造函數
- Empty e2(e1); //拷貝構造函數
- e2 = e1; //賦值運算符
- Empty *pe1 = &e1; //取址運算符(非const)
- const Empty *pe2 = &e2; //取址運算符(const)
C++編譯器對這些函數的實現:
- inline Empty::Empty() //缺省構造函數
- {
- }
- inline Empty::~Empty() //析構函數
- {
- }
- inline Empty *Empty::operator&() //取址運算符(非const)
- {
- return this;
- }
- inline const Empty *Empty::operator&() const //取址運算符(const)
- {
- return this;
- }
- inline Empty::Empty(const Empty &rhs) //拷貝構造函數
- {
- //對類的非靜態數據成員進行以"成員爲單位"逐一拷貝構造
- //固定類型的對象拷貝構造是從源對象到目標對象的"逐位"拷貝
- }
-
- inline Empty& Empty::operator=(const Empty &rhs) //賦值運算符
- {
- //對類的非靜態數據成員進行以"成員爲單位"逐一賦值
- //固定類型的對象賦值是從源對象到目標對象的"逐位"賦值。
- }
例如:m是類C中的一個類型爲T的非靜態成員變量,若C沒有聲明拷貝構造函數(賦值運算符), m將會經過T的拷貝構造函數(賦值運算符)被拷貝構造(賦值);該規則遞歸應用到m的數據成員,直到找到一個拷貝構造函數(賦值運算符)或固定類型(例如:int、double、指針等)爲止。
3、總結
(1)上述運行結果依賴於編譯器和64位、32位不一樣的系統。
(2)本博文只是總結一些C++特性,也有沒法理解的地方,不足之處還請指出,在此先感謝!