拷贝构造函数: 以一个对象的内容去初始化另个对象。 (关键在于初始化)
有三种情况下会调用拷贝构造函数
class x {……};
(1)X x; X xx=x //不是赋值操作而是拷贝构造函数
(2)void foo (X x); // 对象参数
(3)FooBar() { X x; return x;} // 返回对象
如果类没有提供显示的拷贝构造函数,编译器采用的是位逐次拷贝。也就是把对象数据成员值拷贝到另个对象上,如果遇到对象成员就会递归进去。
class String
{
public: //类没有提供显示的拷贝构造函数
private:
char *str ;
int len;
};
class word
{
public: //类没有提供显示的拷贝构造函数
private:
int occurs;
String str: //类含了对象成员
};
位逐次拷贝时先位逐次拷贝int occurs 遇到String后递归进 class String 位逐次拷贝。
当以下情况下编译器不会采用位逐次拷贝,而是生成默认的拷贝构造函数
(1)当类内含一个对象成员,而后者的类中声明了一个拷贝构造函数时 (包括程序员写的,编译器合成的)
class String
{
public:
String (const char *);
String (const String &) //类提供显示的拷贝构造函数
~String();
private:
char *str ;
int len;
};
class word
{
public: //类没有提供显示的拷贝构造函数
private:
int occurs;
String str:
};
//就会合成一个 : word::word(const word &wd) { str.String::String( wd.str); occurs=wd.occurs;}
(2)当类继承一个基类时,而后者存在一个拷贝构造函数时
class word :public String
{
public: //类没有提供显示的拷贝构造函数
private:
int occurs;
String str:
} //就会合成一个
(3)当类声明了虚函数时
class word
{
public: //类没有提供显示的拷贝构造函数
virtural cout(); //类声明了虚函数
private:
int occurs;
String str:
} // 同理与构造函数一样的理由,拷贝构造函数要处理虚函数指针和虚函数表。
(4)当类派生自一个继承链中有虚继承时
class Zoo{…};
class Racconn :public virtual Zoo {….} ;
class ReadPanda : public Racconn {…};
这个时候不是一个类对象要另个类对象做初始化而是基类对象要派生类对象来初始化
Raccoonn rocky; Racconn little=rocky; // 简单的位逐次拷贝就行了
RedPanda litteRed; Racconnn littecritter = rocky ;
// 简单的位逐次拷贝就不行了,编译器必须明确地初始化littercritter 虚继承的指针。