Default Constructor與條款4:确定對象被使用前已先被初始化
《深度探索c++對象模型》2.1 Default Constructor 的構造操作核心在于 default constructors … 在需要的時候被編譯器産生出來這句話,其中暗含編譯器的預設構造函數并不“可靠”,由此《Effectice C++》認為每個class最好擁有顯示的構造函數。
随之帶來的問題是,如何寫好一個高效的構造函數?更具體的,如何配合使用編譯器預設構造函數,使構造函數不至于非常龐雜,同時不産生過多的臨時對象?這就需要了解《深度搜尋c++對象模型》中4個nontrival的構造函數,在這4種情況下,編譯器會輔助自動生成一些代碼:
- “帶有default constructor”的member class object
- “帶有default constructor”的base class object
- "帶有virtual function"的class
- “帶有virtual Base class”的class
3、4條主要關乎虛表相關概念,在了解虛函數、虛基類使用的虛表技術後,便豁然開朗,在此先不作說明。本文重點将放在1、2條,以書上的一個例子進行闡述。
class Dopey {public: Dopey();};
class Sneezy {public:Sneezy(int);Sneezy();...};
class Bashful{public: Bashful();..};
class Snow_White
{
public:
Dopey dopey_;
Sneezy sneezy_;
Bashful bashful_;
private:
int numble_;
string name_;
}
基于第一條原則,若沒有顯示書寫構造函數,編譯器将為其自動生成如下的預設構造函數:
Snow_White::Snow_White()
{
dopey_.Deopy::Doepy();
sneezy_.Sneezy::Sneezy();
bashful_.Bashful::Bashful();
name_.string::string();
}
推薦的顯示構造函數寫法:
Snow_White::Snow_White(int numble,string name):sneezy_(1024),numble_(numble),name_(name)
{}
//将被編譯器擴充成:
Snow_White::Snow_White(int numble,string name)
{
dopey_.Deopy::Doepy();
sneezy_.Sneezy::Sneezy(1024);
bashful_.Bashful::Bashful();
numble_ = numble;
name_.string::string(name);
}
不推薦的寫法如下,在《Effective c++》中認為這種寫法屬于assign而非構造,《深度探索c++對象模型》則表明使用該種寫法,實際是在調用預設拷貝構造函數,而通常情況下預設拷貝構造函數将額外産生一個臨時對象,函數結束還需進行銷毀,是以該寫法是低效的。
Snow_White::Snow_White(int numble,string name):sneezy_(1024)
{
numble_ = numble;
name_ = name;
}
同時值得注意的是,在采用上述推薦寫法時的指派順序,最好按照定義的先後順序進行指派——因為編譯器會強行根據定義順序改變指派順序,確定自身邏輯和編譯器吻合。
class Snow_White
{
public:
Dopey dopey_;
Sneezy sneezy_;
Bashful bashful_;
private:
int numble_;
string name_;
string name2_;
}
//這種寫法編譯器會自動改變
Snow_White::Snow_White(int numble,string name,string name2):sneezy_(1024),numble_(numble),name2_(name2),name(name_)
{}