c++拷贝构造函数简介
拷贝(复制)构造函数、赋值操作符和析构函数总称为复制控制。编译器自动实现这些操作,但类也可以定义自己的版本。编译器自动合成的仅为满足编译器的要求而不是满足用户的要求!
一、拷贝构造函数可用于:
*根据另一个类型的对象显式或者隐式初始化一个对象。
*复制一个对象,将它作为实参传给一个函数。
*从函数返回时复制一个对象。
*初始化顺序容器中的元素。
vector<string> vec(5);
编译器首先使用string默认构造函数创建一个临时值来初始化vec,然后使用复制构造函数将临时值复制到vec的每个元素。
举例:
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
A()
{
cout<<"Construct"<<endl;
}
A(const A &a)
{
cout<<"Cope Construct"<<endl;
}
};
void main()
{
vector<A> vec(5);
}
*根据元素初始化式列表初始化数组元素。
如果没有为类类型数组提供元素初始化式,则将用默认构造函数初始化每个元素。然而,如果使用常规的花括号括住的数组初始化列表来提供显式元素初始化式,则使用复制初始化每个元素。根据指定值创建适当类型的元素,然后用复制构造函数将该值复制到相应元素:
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
A()
{
cout<<"Construct"<<endl;
}
A(int )
{
cout<<"Construct"<<endl;
}
A(const A &a)
{
cout<<"Cope Construct"<<endl;
}
};
void main()
{
A arr[] = {2,3,A()};
}
输出结果:
二、按位拷贝(Bitwise Copy Semantics)!
按位拷贝的含义是每一位都相同,如整数、指针、数组等等也会被复制。这就出现问题了,如果指针也被复制则表明有两个对象要指向同一块内存。
什么时候一个class不展现出"bitwise copy semantics"呢?有四种情况:
1.当class 内含一个member object而后者的class声明有一个copy constructor(不论是显式声明还是编译器合成)时。
2.当class继承自一个base class而后者存在一个copy constructor时(再次强调不论是显式还是编译器合成)。
3.当class声明了一个或多个virtual functions时。因为有vptr,vtable要设置等等
4.当class派生自一个继承串链,其中有一个或者多个virtual base classes时。因为vbptr,vbtable要设置等等。
面对指针成员的拷贝构造函数(也即上面提到的两个对象指向同一块内存问题)怎么处理呢?
一个进行深拷贝,也即在拷贝构造函数里复制指针所指向的对象,这样每个对象的指针就指向了各自的“对象”。
图示如下:
按位拷贝也叫浅拷贝:
拷贝前:
拷贝后:
深拷贝后:
二是进行指针计数,也即当有一个指针指向时指针计数加1,当指针不再指向它时计数减1,计数为0时删除对象。智能指针就是这个原理。
三、复制对象时勿忘每一个成分--记得处理基类内容
class Customer
{
public:
...
private:
string name;
};
class PriorityCustomer : public Customer
{
public:
PriorityCustomer(const PriorityCustomer& rhs);
PriorityCustomer& operator= (const PriorityCustomer& rhs);
private:
int priority;
};
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
: priority(rhs.priority)
{
logCall("PriorityCustomer copy constructor");
}
PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
logCall("PriorityCustomer copy assignment operator");
priority = rhs.priority;
return *this;
}
初看代码感觉一点问题没有,可是它真的没有问题吗?其实它真的有问题!PriorityCustomer的copying函数复制了PriorityCustomer声明的成员变量,但每个PriorityCustomer还内含它所继承的Customer成员变量复件,而那些成员变量却未被复制。
修改如下:
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
: Customer(rhs),priority(rhs.priority)
{
logCall("PriorityCustomer copy constructor");
}
PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
logCall("PriorityCustomer copy assignment operator");
Customer::operator=(rhs);
priority = rhs.priority;
return *this;
}
请记住:
Copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”。
----------------------------------
参考书目:
《C++ Primer》
《深度探索C++对象模型》
《Effective C++》
《More Effective C++》