条款12 : 复制对象时不要忘记其每一个成分
编写一个类用来表现顾客,其中手动写出copying函数使得外界对它们的调用记录会被logged下来:
#include <iostream>
#include <string>
using namespace std;
void logCall(const string funcName)
{
cout<<funcName<<endl;
}
class Customer
{
public:
Customer()
{
}
Customer(const Customer& rhs);
Customer& operator= (const Customer& rhs);
private:
string name;
};
Customer::Customer(const Customer& rhs)
{
this->name = rhs.name;
logCall("拷贝构造函数");
}
Customer& Customer::operator=(const Customer& rhs)
{
logCall("赋值操作符重载");
name = rhs.name;
return *this;
}
int main()
{
Customer c1;
Customer c2(c1);
Customer c3;
c3 = c2;
return 0;
}
上面的函数看起来没有问题,知道一个新的成员变量加入:
#include <iostream>
#include <string>
using namespace std;
void logCall(const string funcName)
{
cout<<funcName<<endl;
}
class Date
{
};
class Customer
{
public:
Customer()
{
}
Customer(const Customer& rhs);
Customer& operator= (const Customer& rhs);
private:
string name;
Date data; //这里增加一个成员变量
};
Customer::Customer(const Customer& rhs)
{
//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
this->name = rhs.name;
logCall("拷贝构造函数");
}
Customer& Customer::operator=(const Customer& rhs)
{
//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
logCall("赋值操作符重载");
name = rhs.name;
return *this;
}
int main()
{
Customer c1;
Customer c2(c1);
Customer c3;
c3 = c2;
return 0;
}
/*
如果你为一个class添加一个成员变量,你必须同时修改copying函数,如果你忘记,
编译器是不会给出任何提示的。
*/
上面说明:如果你为一个class添加一个成员变量,你必须同时修改copying函数
现在让他拥有子类:
#include <iostream>
#include <string>
using namespace std;
void logCall(const string funcName)
{
cout<<funcName<<endl;
}
class Date
{
};
class Customer
{
public:
Customer()
{
}
Customer(const Customer& rhs);
Customer& operator= (const Customer& rhs);
private:
string name;
Date data; //这里增加一个成员变量
};
Customer::Customer(const Customer& rhs)
{
//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
this->name = rhs.name;
logCall("拷贝构造函数");
}
Customer& Customer::operator=(const Customer& rhs)
{
//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
logCall("赋值操作符重载");
name = rhs.name;
return *this;
}
//现在发生了继承
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& PriorityCustomer::operator =(const PriorityCustomer& rhs)
{
logCall("PriorityCustomer copy assignment operator");
priority = rhs.priority;
return *this;
}
/*
PriorityCustomer的copying函数看起来好像复制了PriorityCustomer内的每一样东西,但是仔细看就会发现,
它们复制了PriorityCustomer声明的成员变量,但是每个PriorityCustomer还内含它所继承的Customer成员变
量复件(副本),而这些成员变量却没有被复制。priorityCustome的copy构造函数并没有制定实参传给其base
class构造函数(也就是说它在它的成员初值列表中没有提到Customer),因此PriorityCustomer对象的Customer
成分会被不带实参的Customer构造函数初始化,那么也就是说Customer内的成员变量name和data将执行缺省的初始化。
*/
int main()
{
Customer c1;
Customer c2(c1);
Customer c3;
c3 = c2;
return 0;
}
/*
*/
子类的copy函数只是复制了子类本身加上去的成员变量,但是继承下来的成员变量却没有没复制,怎么解决?
#include <iostream>
#include <string>
using namespace std;
void logCall(const string funcName)
{
cout<<funcName<<endl;
}
class Date
{
};
class Customer
{
public:
Customer()
{
}
Customer(const Customer& rhs);
Customer& operator= (const Customer& rhs);
private:
string name;
Date data; //这里增加一个成员变量
};
Customer::Customer(const Customer& rhs)
{
//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
this->name = rhs.name;
logCall("拷贝构造函数");
}
Customer& Customer::operator=(const Customer& rhs)
{
//函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告
logCall("赋值操作符重载");
name = rhs.name;
return *this;
}
/*
任何时候,只要我们为子类编写copy函数,那我们就必须小心复制其base class成分,而这些成分一般都是private;
所以我们无法直接访问他们,我们能做的就是让子类的copying函数调用相应的base class函数:
*/
class PriorityCustomer:public Customer
{
public:
PriorityCustomer(const PriorityCustomer& rhs);
PriorityCustomer& operator= (const PriorityCustomer& rhs);
private:
int priority;
};
//我们能做的就是让子类的copying函数调用相应的base class函数:
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):Customer(rhs),priority(rhs.priority)//调用base class的copy构造函数
{
logCall("PriorityCustomer copy constructor");
}
//我们能做的就是让子类的copying函数调用相应的base class函数:
PriorityCustomer& PriorityCustomer::operator =(const PriorityCustomer& rhs)
{
logCall("PriorityCustomer copy assignment operator");
Customer::operator =(rhs); //对base class成分进行赋值动作
priority = rhs.priority;
return *this;
}
int main()
{
Customer c1;
Customer c2(c1);
Customer c3;
c3 = c2;
return 0;
}
/*
*/
我们能做的就是让子类的copying函数调用相应的base class函数
总结:
1:Copying函数应该确保复制“对象内的所有成员变量”及所有base class成分
2:不要尝试以某个copying函数实现另外一个copying函数。应该讲共同的机能放进第三个函数当中,并由两个copying函数共同调用。