一、三种情况下的“一个object的内容会作为另一个object对象的初值”
1.显式赋初值
class X{ ... };
X x;
X xx = x;
2. 作为函数形参
void func(X x);
void bar()
{
X x;
//...
func(x);
//...
}
3.当函数返回一个class object时
X foo()
{
X x;
//...
return x;
}
二、Default Memberwise Initialization
该标题的意思是:默认的“为每一个member施以初始化”,那么什么时候才会出发此操作呢?首先看下面的例子:
class String
{
public:
// ... 没有explicit copy constructor
private:
char* str;
int len;
};
一个String object 的Dafault Memberwise Initialization发生再这种情况下:
String str("hello world");
String str2 = str;
// 语意相等
str2.str = str.str;
str2.len = str.len;
请记住:
1.如果class没有提供一个explicit copy destructor,当“一个object的内容会作为另一个object对象的初值”时,其内部操作是以Dafault Memberwise Initialization的手法实现,简单粗暴的讲:把每一个内建的或派生的data member的值,从一个object 拷贝到另外一个object 身上。但是,这并不会拷贝其中的member class object,而是以递归的方式施行memberwise initialization。
2.“如果一个class未定义出copy destructor,编译器就自动为它产生出一个。”这句话不对,而应该像ARM所说:Default constructors和Copy constructors在必要的时候才由编译器产生出来。请注意,是在必要的时候。而本节使用的Dafault Memberwise Initialization手法正是不必要合成拷贝构造函数的时候.必要的时候是类没展现出Bitwise Copy Semantics的时候,而本节的String类恰恰展现出了Bitwise Copy Semantics。
三、Bitwise Copy Semantics
该标题的意思是:位逐次拷贝语意。它关系到编译器是否合成一个Copy constructor。首先看下面的这段代码:
#include "Word.h"
Word noun("book");
void foo()
{
Word verb = noun;
// ...
}
这里verb由noun初始化而来,但在没有看到Word的声明前,我们是不确定这个初始化操作的程序行为。如果类Word的设计者定义了一个copy constructor,那么verb的初始化会调用该拷贝构造函数;如果该class没定义explicit copy constructor,那么编译器一定会合成一个拷贝构造函数被调用。很遗憾,这是错的。这就是本节讨论Bitwise Copy Semantics的目的。
请记住:
如果Word类没有展现 Bitwise Copy Semantics,那么编译器会合成一个拷贝构造函数(用以调用“由编译器合成或设计者显式声明”的member class object的拷贝构造函数);否则,将不合成。
下面来看类是如何表现出Bitwise Copy Semantics的。
// 展现了Bitwise Copy Semantics
class Word
{
public:
Word(const char*);
~Word(){ delete[] str; };
private:
int cnt;
char* str;
};
// 未展现Bitwise Copy Semantics
class Word
{
public:
Word(const String&);
~Word();
private:
int cnt;
String str;
};
其中String 声明了一个explicit copy constructor:
class String
{
public:
String(const char*);
String(const String&);// 声明了显式的拷贝构造函数
~String();
// ...
};
在未展现Bitwise Copy Semantics的情况下,编译器必须合成出一个copy constructor,以便调用member class String object的copy constructor:
// 一个被合成出来的copy constructor
// C++伪码
inline Word::Word(const Word& word)
{
str.String::String(word.str);
cnt = word.cnt;
}
什么时候不展现出Bitwise Copy Semantics呢?有以下四种情况:
1.当class内含一个member class object而后者的class声明了一个copy constructor(不论是编译器合成或设计者显式声明)时。
2.当class继承自一个base class而后者存在一个copy constructor时(再次强调:不论是编译器合成或设计者显式声明)。以上两种情况下,编译器必须将member或base class 的拷贝构造函数调用操作案查倒被合成的copy constructor中。
3.当class 声明了一个或多个virtual funcitons时。
4.当class派生自一个继承串链,其中有一个或多个virtual base classes时。
下面两种情况比较复杂,接下来讨论。
参考文献:《深度探索C++对象模型》侯捷 译