复制控制主要用于用现有的对象去构造一个新的对象,一般通过复制构造函数和赋值操作符实现。如果类没有定义这两个操作方法,那么编译器会为类自动合成(如果编译器认为有必要)。自动合成的复制构造函数和赋值操作符会把各个成员变量的值进行“简单”地拷贝操作,当类成员当中有指针变量时,对指针变量进行简单的复制会造成意想不到后果,本文主要针对类的复制过程当中有指针变量涉及的问题及其解决办法进行介绍。
1、复制构造函数
复制构造函数(copyconstructor)是一种特殊的构造函数,具有单个形参,该形参(通常也是const)是该类引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数,当将该类对象传递给函数或函数返回该类型的对象时,将隐式的使用复制构造函数。如果没有类没有定义复制构造函数,由编译自动为类合成复制构造函数。
1.复制构造可以编译器隐式调用,具体可分为以下几种情况:
(1) 根据另一个同类型的对象显示或隐式的初始化一个对象,通过一个同类对象初始化一个新对象是调用其复制构造函数完成的。
(2) 一个对象,将它作为实参传给一个函数,如果函数(包括成员函数)的参数为类类形的,那么调用过程中先通过复制构造函数构造临时副本,把参数传入函数的栈区,等函数调用返回时再调用类的析构函数,销毁临时副本对象。
(3) 从函数返回一个复制对象,与实参传入函数相同。
(4) 初始化顺序容器的元素。复制构造函数可用于初始化顺序容器中的元素,如vector<Classname>svec(10);编译器使用Classname的默认构造函数创建一个临时对象,后再用复制构造函数来初始化svec元素,每元素重复这个过程。
(5) 根据元素初始化式列表初始化数组
定义类类形数组时,如果没有为类类形数组提供初始化元素,则由默认构造函数初始化一个临时对象后,再用复制构造函数初始化数组元素,如果指定了适当的类型元素,则通过复制构造函数初始化元素。
class Book
{
public:
Book(string name,int num):m_strName(name),m_nNum(num),
m_ptPrice(new double(10.0))
{
cout<<m_strName<<" Constructor"<<endl;
}
Book(string name = "default"):m_strName(name)
{
m_nNum = 100;
m_ptPrice = new double(999);
cout<<m_strName<<" Constructor"<<endl;
}
Book(const Book &b)
{
m_nNum = b.m_nNum;
m_strName = b.m_strName;
m_ptPrice = new double(*b.m_ptPrice);
cout<<m_strName<<" copy constructor..."<<endl;
}
const Book operator=(const Book b)
{
m_nNum = b.m_nNum;
m_strName = b.m_strName;
m_ptPrice = new double(*b.m_ptPrice);
cout<<m_strName<<" operator= call..."<