条款12 复制对象时勿忘其每一个成分
面向对象系统会将对象的内部封装起来,只留两个函数负责对象的copy:即copy构造函数和赋值运算符。
当用户没有实现时,编译器会自动为对象生成这两个函数,对对象的所有参数做值copy,[浅copy]。
因此,对于在构造函数中使用new的class,要额外注意copy构造和赋值运算符。
编译器默认生成的构造函数,并不会copy new出来的对象,只复制了其地址,直接使用编译器生成的函数会有意想不到的问题。
class Account
{
public :
Account(std::string str ):data_(str) {}
~Account() {}
std::string data_;
};
class Customer
{
public:
Customer(const std::string name,std::string mobile_num):name_(name)
{
mobile_ = new Account(mobile_num);
}
~Customer()
{
delete mobile_;
}
/*
Customer(const Customer &rhs):
name_(rhs.name_)
{
mobile_ = new Account(rhs.mobile_->data_);
}
*/
void Print()
{
std::cout << name_ << " mobile account is " << mobile_->data_ << std::endl;
}
private:
std::string name_;
Account *mobile_;
};
int main(int argc, char const *argv[])
{
{
Customer *A =new Customer("ys","13888888888");
A->Print();
Customer B(*A);
delete A;
B.Print(); // 无法正常打印数据,没有手机号了
// 析构B时会Crash ,对同一块内存delete了两次。
}
return 0;
}
自定义子类的copy和赋值运算符时不要忽略基类的构造。
class VipCustomer:public Customer
{
public:
VipCustomer(std::string name,double free):Customer(name),free_(free)
{
}
~VipCustomer() {}
//VipCustomer(const VipCustomer &rhs):free_(rhs.free_) // error ,not copy Base class ,can not complie
VipCustomer(const VipCustomer &rhs):Customer(rhs),free_(rhs.free_)
{
logCall("drive copy constructor called ");
}
private:
double free_;
};
int main(int argc, char const *argv[])
{
VipCustomer A("ys",0.4);
VipCustomer B(A);
return 0;
}
应copy所有的成员变量。
class Date
{
public :
Date() {}
~Date() {}
int year;
int month;
int day;
};
class Customer
{
public:
Customer(const std::string name):name_(name){}
~Customer(){}
Customer(const Customer &rhs):name_(rhs.name_)
{
logCall("copy constructor called ");
}
private:
void logCall(std::string str)
{
std::cout<< Date.year<<"-"<< Date.month<<"-" <<Date.day<<": "<< str <<std::endl;
}
private:
std::string name_;
Date last_date_;
};
如上,copy构造函数没有复制Date成员变量,会导致构造的新的实例里的Date对象未知。