天天看点

《深度探索c++对象模型》与《Effective c++》读书笔记

Default Constructor与条款4:确定对象被使用前已先被初始化

  《深度探索c++对象模型》2.1 Default Constructor 的构造操作核心在于 default constructors … 在需要的时候被编译器产生出来这句话,其中暗含编译器的默认构造函数并不“可靠”,由此《Effectice C++》认为每个class最好拥有显示的构造函数。

  随之带来的问题是,如何写好一个高效的构造函数?更具体的,如何配合使用编译器默认构造函数,使构造函数不至于非常庞杂,同时不产生过多的临时对象?这就需要理解《深度搜索c++对象模型》中4个nontrival的构造函数,在这4种情况下,编译器会辅助自动生成一些代码:

  1. “带有default constructor”的member class object
  2. “带有default constructor”的base class object
  3. "带有virtual function"的class
  4. “带有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_)
{}

           

继续阅读