編譯器合成缺省(無參)的構造函數ios
這個能夠從語言設計的角度來看這個問題。體現一個實例化的對象生命週期的完整性,一個對象在初始化的時候,讓使用者有機會作些額外的初始化操做。一樣,一個對象是消亡的時候,也要使用者有機會去釋放資源。舉個例子:吃飯前先洗手(構造函數),吃完飯在擦嘴(析構函數),這是個好習慣。可是你不洗手,不擦嘴,也不要緊,只是這不是個好習慣而已(偶爾形成細菌感染,程序異常)。c++
好習慣的養成是一個持續的過程,因此有時候編譯器會偷偷的幫你洗手擦嘴。程序員
A.間接的含有構造函數,好比類成員變量含有構造函數,或者是繼承的父類有構造函數。函數
B.直接或者間接的含有virtual function,好比本身含有virtual function或者是類成員變量,或者是繼承的父類含有。測試
C.出現虛繼承的現象。ui
拷貝構造和缺省的構造也是一樣的A,B,C狀況下,編譯器會合成默認的拷貝構造。固然編譯器生成的拷貝構造就是淺拷貝。spa
// 沒有析構函數的類
class NoDctorClass {
public:
int m_a;
};
// 測試編譯器合成析構函數
void test_compiler_geneator_def_dctor() {
NoDctorClass no_dctor_class;
// 調用析構函數
no_dctor_class.~NoDctorClass();
no_dctor_class.m_a = 0;
}
// 轉到反彙編的代碼
// NoDctorClass no_dctor_class;
// 調用析構函數,這裏沒有生成任何的反彙編代碼
// no_dctor_class.~NoDctorClass();
// no_dctor_class.m_a = 0;
012AA9FE mov dword ptr [no_dctor_class],0
複製代碼
簡單一句話,編譯器須要插入一些額外的初始化代碼,來完成一些語言特性。翻譯
A.間接的含有缺省構造函數,這時候編譯器發現你本身沒有寫構造函數,可是你又間接含有構造函數。編譯器這時候有兩種作法,一種是心想算了吧我幫你偷偷的生成一個吧,還有一種作法就是編譯器報語法錯,讓程序員本身解決。因此編譯器廠商一商量以爲仍是對程序員友好一點,用第一種作法吧。反過來想,若是一門開發語言對程序員不友好,能夠說是它的生存期將會很是短。設計
B.直接或者間接的含有virtual function,由於含有virtual function,爲了支持多態的特性,那麼每一個實例對象都會生成指向虛函數表的指針。可是這個指針在何時初始化呢?天然是(拷貝)構造函數裏面。可是你本身沒有寫,編譯器只好累一點生成(拷貝)構造函數。指針
C.虛繼承狀況,爲了不子類中含有多餘的成員變量,對象在實例化的時候會生成指向虛基類表的指針。天然就會聯想到在(拷貝)構造函數的時候生成,一樣你本身沒有寫,編譯器管家來替你寫。
1.在你的菜單欄找到以下控制檯
2.cd到編譯生成目錄下,找到你生成的obj文件,好比我生成main.obj。
3.執行 dumpbin.exe /all main.obj >> main.txt,將文件格式翻譯爲COFF。
4.查看main.txt 找到,若是所示找到1所對應的函數,下面的2就是編譯器準備插入的代碼,能夠看到插入了MatrixA的構造函數。同理,能夠驗證其餘的狀況。
2.儘可能不要依賴編譯器的操做。
3.要站在編譯器的角度去看問題。
構造函數和拷貝構造是你的左膀右臂,建議仍是得要好好的利用。儘管有時候你不認可,可是編譯器這個管家仍是會偷偷摸摸的給你裝個左膀右臂。若是說構造函數是你的左膀右臂,那麼析構函數就是你的一把強有力的武器用於保護本身,在對象生命結束以後可以確保資源的正常釋放。
/**************************************************************************** ** ** Copyright (C) 2019 635672377@qq.com ** All rights reserved. ** ****************************************************************************/
/* 測試編譯器在何種狀況會合成默認的構造函數 同理可證:在何種狀況下編譯器會合成默認的拷貝構造函數 */
#ifndef default_constrcuctor_h
#define default_constrcuctor_h
#include <iostream>
using std::cout;
using std::endl;
namespace defualt_constructor
{
// 含有缺省的構造函數成員類對象
// #define has_default_ctor_member 1
// 繼承含有缺省的構造函數
// #define has_inherit_ctor_base 1
// 含有虛函數成員函數
// #define has_virtual_function 1
// 函數virtual函數的成員類對象
// #define has_virtual_func_member 1
// 父類含有虛函數
// #define has_inherit_virtual_func_base 1
// MatrixC, MatrixB 虛繼承MatrixD
// #define has_virtual_inherit_base 1
// 類成員變量含有copy ctor
// #define has_default_copy_ctor_member 1
// 父類含有拷貝構造函數
#define has_inherit_copy_ctor_base 1
// 含有虛函數成員函數
// #define has_virtual_function_copy_ctor 1
// 類對象成員含有虛函數
// #define has_virtual_function_copy_ctor_member 1
// 父類函數虛函數
// #define has_inherit_virtual_function_copy_ctor_base 1
// 虛繼承copy ctor
// #define has_virtual_inherit_function_copy_ctor_base 1
class MatrixD {
};
#ifdef has_virtual_inherit_base
class MatrixC : virtual public MatrixD
#elif has_virtual_inherit_function_copy_ctor_base
class MatrixC : virtual public MatrixD
#else
class MatrixC #endif // has_virtual_inherit_base {
public:
#ifdef has_inherit_ctor_base
MatrixC() { cout << "MatrixC" << endl; }
#elif has_inherit_copy_ctor_base
MatrixC() {}
MatrixC(const MatrixC &rhs) { cout << "MatrixC copy ctor" << endl; }
#elif has_inherit_virtual_function_copy_ctor_base
virtual void VirFun() {}
#elif has_inherit_virtual_func_base
virtual void VirFun() {}
#endif // has_virtual_inherit_base
};
#ifdef has_virtual_inherit_base
class MatrixB : virtual public MatrixD
#elif has_virtual_inherit_function_copy_ctor_base
class MatrixB : virtual public MatrixD
#else
class MatrixB #endif // has_virtual_inherit_base {
public:
#ifdef has_default_ctor_member
MatrixB() { cout << "MatrixB" << endl; }
#elif has_virtual_func_member
virtual void VirMatrixB() { cout << "virtual MatrixB" << endl; }
#elif has_default_copy_ctor_member
MatrixB() {}
MatrixB(const MatrixB &rhs) { cout << "copy ctor MatrixB" << endl; }
#elif has_virtual_function_copy_ctor_member
virtual void VirMatrixB() { cout << "virtual MatrixB" << endl; }
#endif // has_default_ctor_member
int m_high;
int m_width;
};
#ifdef has_default_ctor_member
class MatrixA #elif has_virtual_function class MatrixA #elif has_inherit_ctor_base class MatrixA : public MatrixC
#elif has_inherit_copy_ctor_base
class MatrixA : public MatrixC
#elif has_virtual_func_member
class MatrixA #elif has_virtual_inherit_base class MatrixA : public MatrixB, public MatrixC
#elif has_inherit_virtual_func_base
class MatrixA: public MatrixC
#elif has_inherit_virtual_function_copy_ctor_base
class MatrixA : public MatrixC
#elif has_virtual_inherit_function_copy_ctor_base
class MatrixA : public MatrixB, public MatrixC
#else
class MatrixA #endif // has_default_ctor_member {
public:
int m_age;
int m_score;
#ifdef has_default_ctor_member
MatrixB matrixB;
#elif has_virtual_function
virtual void VirFunc() { cout << "virtual function" << endl; }
#elif has_virtual_func_member
MatrixB matrixB;
#elif has_default_copy_ctor_member
MatrixA() {}
MatrixB matrixB;
#elif has_inherit_copy_ctor_base
MatrixA() {}
#elif has_virtual_function_copy_ctor
virtual void VirFunc() { cout << "virtual function" << endl; }
#elif has_virtual_function_copy_ctor_member
MatrixB matrixB;
#endif // has_default_ctor_member
};
void test_compiler_generator_def_ctor() {
//用dumpbin把.obj文件內容導出成可查看文件my.txt,
// 這個my.txt格式,通常被認爲是COFF:通用對象文件格式(Common Object File Format);
MatrixA matrix;
matrix.m_age = 0;
// 編譯器會在哪些狀況下合成默認的構造函數?
// 1.包含一個類成員變量,此成員變量含有默認的缺省構造函數。此時編譯器就會
// 生成默認的構造函數。在這個合成的構造函數中插入代碼調用成員變量的構造函數
// 2.繼承的父類含有缺省的構造函數,此時編譯器也會構造默認的構造函數,在子類合成的構造
// 函數中插入代碼,調用父類的缺省構造
// 3.包含虛函數。不論是子類,父類,仍是包含的成員類對象(不包含任何構造函數),只要
// 包含了virtual function,編譯器都會合成默認的構造函數
// 4.含有虛繼承現象,grandfather, parent(虛繼承grand),child再繼承,
// 爲了在構造函數中生成vbtable,虛基類表
// 一樣的道理,copy constrcutor也和constructor也是在一樣的狀況下,編譯器會合成默認
// 的構造函數
// A.含有默認的構造函數
// 1.父類有默認的構造函數
// 2.包含類對象的成員變量含有默認構造函數
// B.虛函數
// 1.不論是本身包含虛函數,仍是類成員變量有虛函數,仍是父類中虛函數
// C.虛繼承
// 1.編譯器爲了在插入vbtable 虛基類表
}
void test_compiler_generator_def_copy_ctor() {
MatrixA ma;
MatrixA mb = ma;
// 編譯器合成默認copy ctor時機和ctor是同樣的
}
}
#endif // default_constrctor_h
複製代碼