您的位置:首页 > 编程语言 > C语言/C++

深入探索C++对象模型笔记之四 —— 构造函数语意学 (Copy Constructor的建构操作)

2011-05-26 19:14 441 查看
有三种情况,会以一个object的内容作为另一个class object的初值。

1.当对一个object做明确的初始化操作时

2.当object被当做参数交给某个函数时

3.当函数传回一个class object时

以上三种情况都会导致copy constructor的调用。

Default Memberwise Initialization

如果class没有提供一个explicit copy constructor,编译器会怎么做呢?

当class object以“相同的class的另一个object”作为初值时,其内部是以所谓的default memberwise initialization手法完成的,也就是把每一个内建的或派生的data member的值,从某个object拷贝一份到另一个object身上,不过它并不会拷贝其中的member class object,而是以递归的方式(也就是继续调用member class object的copy constructor函数)施行memberwise initialization。

这样的操作实际上如何完成?ARM告诉我们:

“从概念上而言,对于一个class X,这个操作是被一个copy constructor实现出来...”

其中主要的字眼是“概念上”,这个注释又紧跟着一些解释:

“一个良好的编译器可以为大部分class objects 产生bitwise copies,因为它们有bitwise copy semantics...”

也就是说,“如果一个class未定义出copy constructor,编译器自动为它产生出一个”这句话不对,而是应该像ARM所说:

“Default constructor和copy constructor在必要的时候才由编译器产生出来.”

这个句子中的“必要”意指当class不展现bitwise copy semantics时。

C++ Standard 说:

“一个class object可以从两种方式复制得到,一种是被初始化,一种是被指定(assignment),从概念上讲,这两个操作分别是以copy constructor和copy assignment operator 完成的。”

Bitwise Copy Semantics(位逐次拷贝)

#include "Word.h"

Word noun("book");

void foo()

{

Word verb = noun;

...

}

很明显verb是根据noun来初始化。但是在尚未看过class Word的声明之前,我们不可能预测这个初始化操作的程序行为。如果class Word的设计者定义了一个copy constructor,verb的初始化操作会调用它。如果该class没有定义explicit copy constructor,那么是否会有一个编译器合成的实体被调用呢 ?这就得视该class是否展现“bitwise copy semantics”而定。

例如:

class Word

{

public:

Word(const char*);

~Word(delete [] str);

private:

int cnt;

char* str;

}

这种情况下并不需要合成出一个default copy constructor,因为上述声明展现了“default copy semantics”,而verb的初始化操作也不需要以一个函数调用收场。(但是这里会有明显的浅拷贝错误)然而,如果class Word是这样声明:

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();

};

在这个情况下,编译器必须合成出一个copy constructor以便调用member class String object 的copy constructor:

inline Word::Word(const Word& wd)

{

str.String::String(wd.str);

cnt = wd.cnt;

}

有一点很值得注意:在这被合成出来的copy constructor中,如整数、指针、数组等等的nonclass members也都会被复制。

四种情况下一个class不展现出“bitwise copy semantics”:

1.当class内含一个member object而后者的class声明有一个copy constructor时。(不论是明确声明还是由编译器合成而来)

2.当class继承自一个base class而后者存在一个copy constructor时。(不论是明确 声明还是由编译器合成而来)

3.当class声明了一个或多个virtual function时。

4.当class派生自一个继承串链,其中有一个或多个virtual base classes 时。

下面说明第三条和第四条。

第三条:如果class声明了一个或多个virtual function时,编译器会将一个指向virtual function table的指针(vptr)安插在每一个class object内。很显然,如果编译器对于每一个新产生的class object的vptr不能成功而正确地设好其初值,将导致可怕的后果。因此,当编译器导入一个vptr到class之中时,该class就不再展现bitwise semantics了。现在,编译器需要合成出一个copy constructor,以求将vptr适当地初始化。

第四条:virtual base class的存在需要特别处理,一个class object如果以另一个object作为初值,而后者有一个virtual base class subobject,那么也会使“bitwise copy semantics”失效。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: