}
如果一个类中有指针成员,使用缺省的复制构造函数初始化对象就会出现问题。为了说明存在的问题,我们假定对象A与对象B是相同的类,有一个指针成员,指向对象C。当用对象B初始化对象A时,缺省的复制构造函数将B中每一个成员的值复制到A的对应的成员当中,但并没有复制对象C。也就是说,对象A和对象B中的指针成员均指向对象C,实际上,我们希望对象C也被复制,得到C的对象副本D。否则,当对象A和B销毁时,会对对象C的内存区重复释放,而导致错误。为了使对象C也被复制,就必须显式定义复制构造函数。下面我们以string类为例说明,如何定义这个复制构造函数。
例10-11
class String
{
public:
String(); //构造函数
String(const String &s); //复制构造函数
~String(); //析构函数
// 接口函数
void set(char const *data);
char const *get(void);
private:
char *str; //数据成员ptr指向分配的字符串
};
String ::String(const String &s)
{
str = new char[strlen(s.str) + 1];
strcpy(str, s.str);
}
我们也常用无名对象初始化另一个对象,例如:
Point pt = Point(10, 20);
类名直接调用构造函数就生成了一个无名对象,上式用左边的无名对象初始化右边的pt对象。
构造函数被调用通常发生在以下三种情况,第一种情况就是我们上面看到的:用一个对象初始化另一个对象时;第二种情况是当对象作函数参数,实参传给形参时;第三种情况是程序运行过程中创建其它临时对象时。下面我们再举一个例子,就第二种情况和第三种情况进行说明:
Point foo(Point pt)
{
…
return pt;
}
void main()
{
Point pt1 = Point(10, 20);
Point pt2;
…
pt2=foo(pt);
…
}
在main函数中调用foo函数时,实参pt传给形参pt,将实参pt复制给形参pt,要调用复制构造函数,当函数foo返回时,要创建一个pt的临时对象,此时也要调用复制构造函数。
缺省的复制构造函数
在类的定义中,如果没有显式定义复制构造函数,C++编译器会自动地定义一个缺省的复制构造函数。下面是使用复制构造函数的一个例子:
例10-12
#include
#include
class withCC
{
public:
withCC(){}
withCC(const withCC&)
{
cout<<"withCC(withCC&)"<
};
class woCC
{
enum{bsz = 100};
char buf[bsz];
public:
woCC(const char* msg = 0)
{
memset(buf, 0, bsz);
if(msg) strncpy(buf, msg, bsz);
}
void print(const char* msg = 0)const
{
if(msg) cout<
};
class composite
{
withCC WITHCC;
woCC WOCC;
public:
composite() : WOCC("composite()"){}
void print(const char* msg = 0)
{
WOCC.print(msg);
}
};
void main()
{
composite c;
c.print("contents of c");
cout<<"calling composite copy-constructor"<
c2.print("contents of c2");
}
类withCC有一个复制构造函数,类woCC和类composite都没有显式定义复制构造函数。如果在类中没有显式定义复制构造函数,则编译器将自动地创建一个缺省的构造函数。不过在这种情况下,这个构造函数什么也不作。
类composite既含有withCC类的成员对象又含有woCC类的成员对象,它使用无参的构造函数创建withCC类的对象WITHCC(注意内嵌的对象WOCC的初始化方法)。
在main()函数中,语句:
composite c2 = c;
通过对象C初始化对象c2,缺省的复制构造函数被调用。
最好的方法是创建自己的复制构造函数而不要指望编译器创建,这样就能保证程序在我们自己的控制之下。
摘自 飘过的小牛