Inside the C++ Object Model学习笔记[Chap2.2]

来源:互联网 发布:淘宝上装修公司靠谱吗 编辑:程序博客网 时间:2024/05/16 08:14
 

2.2 Copy Constructor建构操作

2.2.1 调用Copy Constructor的三种情况

1. 用一个类对象的内容对另一个对象作明确的初始化操作,如

2. 当对象被当作参数传给某个函数时,如

3. 当函数传回一个类对象时,如

class X { …… };

void func( X x ) { …… }

X func() {

       X xx;

       return xx;

}

X x1;

X x2 = x1;   //----

func( x1 );   //----

func();      //----

注意:用户定义的拷贝构造函数可以带多参数,如:X::X(const X& x, int = 0);

2.2.2 默认memberwise initialization

在类没有提供一个显式的拷贝构造函数时,当类对象以“相同类的另一个对象”作为初值时,其内部从逻辑上说以所谓的default memberwise initialization方式完成的,也就是说把每一个内建的或派生的数据成员(如数组或指针)的值,从某个对象拷贝一份到另外一个对象,但对于其中的成员类对象,则采用调用该成员类的拷贝构造函数完成(若涉及到派生,那么递归调用其基类的拷贝构造函数),如:

class String {

       private:

              char* str;

              int len;

};

String noun(“book”);

String verb = noun;

Memberwise initialization的意义如下:

verb.str = noun.str;

verb.len = noun.len;

至于什么时候产生默认的拷贝构造函数(指nontrivial类型,而编译器总产生trivial类型的拷贝构造函数),跟默认构造函数的产生一样,编译器只在必要的时候才产生,也就是说类不存在bitwise拷贝语意时(为便于理解,不存在bitwise拷贝语意的四种情况为:类内含有带拷贝构造函数的成员类对象;类所继承的基类含拷贝构造函数;类声明了虚函数;类的继承体系中存在抽象基类,除了以上四种情况,类都存在bitwise语意,在此情况下,编译器默认的拷贝构造函数为trivial类型,只作memberwise意义上的拷贝)。按照thinking in c++11.3.4节所述,仅当准备按值传递的方式传递类对象是,才需要拷贝构造函数,否则就不需要。

如果设计者定义了自己的拷贝构造函数,那么就会调用设计者所定义的函数。

2.2.3 bitwise copy

Bitwise copy的意义实际上是逻辑memberwise的具体实现,按照位的方式对类对象中的成员一个一个地拷贝,如:

class Word {

       public:

              Word( const char* );

              ~Word() { delete [] str; }

       private:

              int cnt;

              char* str;

};

对于memberwisebitwise的理解问题,我认为仅仅只是角度不一样,memberwise是从概念上而bitwise从实现上分别说明拷贝构造函数的默认意义。

存在的问题:1. 造成内存泄漏;2. 对同一块内存多次删除问题。

2.2.4 bitwise copy语意

在以下四种情况下,类不展现bitwise copy语意:(同默认构造函数类似)

1. 类内部含有成员类对象,而后者声明有一个拷贝构造函数(不管是显式声明,还是隐式由编译器合成),如下例:

class String {

       public:

              String( const char* );

              String( const String& );  //显式拷贝构造函数

};

class Word {

       public:

              Word( const String& );  //构造函数,无显式拷贝构造函数

       protected:

              int cnt;

              String str;

};

Word类,编译器必须隐式合成一个nontrivial拷贝构造函数:

inline Word::Word( const Word& wd) {

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

       cnt = wd.cnt;  //注意合成的拷贝构造函数中,所有成员都会被复制

}

2. 当类所继承的基类存在一个拷贝构造函数时,不管是显式还是隐式情况,如:

class Article : public Word { //Word1.中定义的类

       private:

              int num;

};

那么,编译器隐式合成的nontrivial拷贝构造函数如下:

inline Article::Article( const Article& al ) {

       str.String::String( al.str );

       cnt = al.cnt;

       num = al.num;

}

3. 类中声明了一个或多个虚函数时;

如是相同类型的对象相互之间拷贝时,虚函数的vptr由编译器设定vptr为指向该类的vtbl即可(参见书――P55图),如:

class ZooAnimal {

       public:

              virtual ~ZooAnimal();

              virtual void animate();

              virtual void draw();

};

class Bear : public ZooAnimal {

       public:

              void animate();

              void draw();

              virtual void dance();

};

Bear b;

Bear b1 = b;  //vptr指向Bearvtbl

ZooAnimal za = b; //发生切割问题,并且vptr的指向应该为ZooAnimalvtbl

但如果是派生类对象拷贝给基类对象时(会存在切割问题),vptr的复制操作必须保证指向正确的vtbl,即拷贝给基类的vptr必须重新由编译器设置为指向基类的vtbl,而不是派生类的vtbl(参见书――P56图)。这种情况下,显然bitwise的拷贝操作不可能做到。

4. 类的继承体系中,所继承的类有一个或多个抽象基类时。

同上一种情况类似,需要重新设置vptr的指向问题,也存在切割问题。

原创粉丝点击