类名(类名 const& 参数名)
{
函数体
}
//此类情况使用浅拷贝
class Cperson
{
private:
int a;
public:
Cperson(Cperson const& other);//拷贝构造
}
Cperson::Cperson(Cperson const& other)
{
this->a=other.a;
}
//此类含有指针的情况使用深拷贝
class Cperson
{
private:
int age;
char* name;
public:
Cperson(Cperson const& other);
}
Cperson::Cperson(Cperson const& other)
{
this->age=other->age;
if (other.name)//深拷贝
{
int len = strlen(other.name);
this->name = new char[len+1];
strcpy(this->name, other.name);
}
else
this->name = NULL;
}
int main()
{
Cperson person1;
Cperson person2(person1);//隐式调用拷贝构造
Cperson person2=person1;//显示调用拷贝构造
}
每个成员的类型绝对了它如何被拷贝:
string dots(10,'.'); //直接初始化
string s(dots); //直接初始化
string s2=dots; //直接初始化
string null_book="9-999-99999-9";//拷贝初始化
string nines=string(100,'9'); //拷贝初始化
附加:
拷贝初始化不仅在我们使用=定义变量时会发生,在下列情况下也会发生:
●将一个对象作为实参传递给- -个非引用类型的形参
●从一个返回类型为非引用类型的函数返回一个对象
●用花括号列表初始化-一个数组中的元素或--个聚合类中的成员
class Sales_data{
public:
Sales_data(const Sales_data&)=default;
}
我们只能对具有合成版本的成员函数使用=default(即,默认构造函数或拷
贝控制成员)。
例如:
string null_book="9-999-9999-9"; //拷贝初始化
改写为:
string null_book("9-999-9999-9"); //编译器略过了拷贝构造函数
class A;
A a;
A b = a; // 调用拷贝构造函数, 因为b是第一次初始化
A c(a); // 调用拷贝构造函数, 因为c是第一次初始化
b = c; // 调用赋值运算符, 因为b已经初始化过了
class HasPtr{
public:
HasPtr(const std::string &s=std::
string()):ps(new std::string(s)),i(0){}
~HasPtr(){delete ps;}
private:
std::string *ps;
int i;
}
HasPtr f(HasPtr hp)
{
HasPtr ret=hp; //拷贝给定的HasPtr
return ret; //ret和hp被销毁
}
当f返回时,hp和ret都被销毁,在两个对象上都会调用HasPtr的析构函数。此析构函数会delete ret和hp中的指针成员。但这两个对象包含相同的指针值。此代码会导致此指针被delete两次,这显然是一一个错误(参见12.1.2 节,第411页)。将要发生什么是未定义的。
此外,f的调用者还会使用传递给f的对象:
HasPtr p ("some values") ;
f(p) ;//当f结束时,p.ps指向的内存被释放
HasPtr q(p);//现在p和q都指向无效内存!
P (以及q)指向的内存不再有效,在hp (或ret!) 销毁时它就被归还给系统了。
虽然很多类需要定义所有(或是不需要定义任何)拷贝控制成员,但某些类所要完成的工作,只需要拷贝或赋值操作,不需要析构函数。
作为一个例子,考虑一个类为每个对象分配一个独有的、 唯一的序号。这个类需要一个拷贝构造函数为每个新创建的对象生成一个新的、独一无二的序号。除此之外,这个拷贝构造函数从给定对象拷贝所有其他数据成员。这个类还需要自定义拷贝赋值运算符来避免将序号赋予目的对象。但是,这个类不需要自定义析构函数。
这个例子引出了第二个基本原则:如果一个类需要一个拷 贝构造函数,几乎可以肯定它也需要一个拷 贝赋值运算符。反之亦然一如果一个类需要一个拷贝赋值运算符,几乎可以肯定它也需要一个拷贝构造函数。然而,无论是需要拷贝构造函数还是需要拷贝赋值运算符都不必然意味着也需要析构函数。
class Cperson
{
private:
int age;
char* name;
public:
Cperson(Cperson const& other);
}
Cperson::Cperson(Cperson const& other)
{
this->age=other.age;
this->name=other.name;//错误做法
}