2.2 Copy Constructor

     将一个object的内容作为另一个class object的初值的三种情况:

(a)明确的初始化操作

class X{...}
X x;
X xx=x;
(b)作为函数的参数

extern void foo(X x);

void bar()
{
   X xx;
   //以xx作为foo()第一个参数的初值(不明显的初始化操作)
   foo(xx);
}


(c)作为函数返回值

X foo_bar()
{
   X xx;
   return xx;
}


一、Default Memberwise Initialization (不是默认构造函数的情况)

       如果明确定义了copy constructor,则发生上述三种情况时,会调用这些copy constructor。

X::x(const X& x);
Y::y(cons tY& y, int = 0) ;

      如果没有提供一个明确的(explicit)copy constructor,会把每一个内建的或派生的data member(一个指针或数组)的值从某个object拷贝一份到另一个object中,着被称为 Default Memberwise Initialization 。不过这不会拷贝其中的member class object,而是以递归的方式施行memberwise initialization。

(a)default member wiseinitialization

#include<iostream>
#include<stdlib.h>
using namespace std;

class String{
public:
    //...没有explicit copy constructor
    String(char* s):str(s){
        for(len=0;s[len]!='\0';++len);
    };

private:
    friend ostream& operator<< (ostream& os,const String& s);
    char *str;
    int len;
};

ostream& operator<< (ostream& os,const String& s)
{
    os<<"str:"<<s.str<<", "<<"len:"<<s.len;
    //os<<"yes"<<endl;
    return os;

}

int main()
{
    String noun("book");
    cout<<"noun:"<<noun<<endl;
    String verb=noun;
    cout<<"verb:"<<verb<<endl;
    system("pause");
    return 0;
}


(b)递归方式的Member Initialization

#include<iostream>
#include<stdlib.h>
using namespace std;

class String{
public:
    //...没有explicit copy constructor
    String(char* s):str(s){
        for(len=0;s[len]!='\0';++len);
    };

private:
    friend ostream& operator<< (ostream& os,const String& s);
    char *str;
    int len;
};

class Word{
public:
    Word(int o,String s):_occurs(o),_word(s){}
    void print();
private:
    int _occurs;
    String _word;
};
void Word::print(){
    cout<<_word<<endl;
}
ostream& operator<< (ostream& os,const String& s)
{
    os<<"str:"<<s.str<<", "<<"len:"<<s.len;
    return os;

}

int main()
{
    String noun("book");
    Word w1(5,noun);
    Word w2=w1;
    cout<<"w1:";
    w1.print();
    cout<<"w2:";
    w2.print();
    system("pause");
    return 0;
}


★Default constructors和copy constructors在必要的时候才由编译器产生出来


二、bitwise copy senmantics

(a)不需要合成default copy constructor

class Word{
public: 
    word(const char*);
    ~word(){delete []str;}
private:
   int cnt;
   char *str;
}
上述情况不需要合成默认的复制构造函数,因为其展现了“default copy semantics”,但可能发生内存泄露,


(b)必须合成一个copy constructor以便调用member class String的 copy constructor

//一个被合成的copyconstructor
//伪码
inline Word::word(const Word& wd)
{
   str.String::String(wd.str);
   cnt=wd.cnt;
}
被合成的copy constrcutor中,整数、指针、数组等nonclass members也都会被复制。


二、不要bitwise copy semantics的四种情况

1.当class 内含一个member object而后者的class声明有一个copy constructor时(无论明确声明或被编译器合成)

2.当class继承自一个base class而后者存在有一个copy constructor(无论明确声明或被编译器合成)

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

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

前两种情况,编译器必须把member或base class 的copy constructor安插到被合成的constructor中。


三、重新设定virtual table 指针

■增加一个virtual funcation table(vtbl),内含每一个有作用的virtual function的地址

将一个指向virtual function table的指针(vtpr)安插在每一个class object内

当编译器导入一个vptr到class之中,该class就不在展现bitwise semantics,编译器需要合成一个copy constructor,以求将vptr初始化。

class ZooAnimal{
    public:
        ZooAnimal();
        virtual ZooAnimal();
        virtual void animate();
        virtual void draw();
private:
//一些数据。。。
};

class Bear:publicZooAnimal{
public:
    Bear();
    void animate();//未写明,为virtual
    void draw();//未写明,为virtual
    virtual void dance();
private:
    //所需一些数据...
};


同类型的class object作为初值,都可用“bitwise copy semantics”

Bear yogi;
Bear winnie = yogi;
此时yogi被default Bear constructor初始化,在constructor中,yogi的vptrvptr被指向Bear class的virtual table


ZooAnimal franny = yogi

franny的vptr不可以被设定指向Bear class的virtual table。

void draw(const ZooAnimal& zoey){zoey.draw();}
void foo()
{
     ZooAnimal franny=yogi;
     draw(yogi);   //调用Bear::draw();
     draw(franny);//调用ZooAnimal::draw();
}
上例说明合成出来的ZooAnimal的copy constructor会明确设定object的vptr指向ZooAnimal class的virtual table,而不是直接拷贝。


四、处理virtual base class subobject

      一个virtual base class的存在会使bitwise copy semantics无效。

class Reccoon: public virtual ZooAnimal{
public:
      Reccoonn(){}
      Reccoonn(int val){}
private:
   //必要的数据
};

class RedPanda:public Raccoon{
public:
    RedPanda(){}
    RedPanda(int val){}
private:
    //....
};
Raccoon rocky;
Raccoon little_critter = rocky;

此时,编译器必须合成一个copy constructor,安插一些码来设定virtual base class pointer/offset



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值