问题聚焦:
负责拷贝的两个操作:拷贝构造函数和重载赋值操作符。
一句话总结,确保被拷贝对象的所有成员变量都做一份拷贝。

Demo
 
void logCall(const std::string& funcName);  // log函数

class Date{ ... };

class Customer {
public:
....
Customer(const Customer& rhs);
Customer& operator=(const Customer& rhs);
private:
std::string name;
Date lastTransaction;
}; Customer::Customer(const Customer& rhs)
: name(rhs.name) // 忽略了lastTransaction成员变量
{
logCall("Customer copy constructor");
} Customer& Customer::operato=(const Customer& rhs)
{
logCall("Customer copy assignment operator");
name = rhs.name; // 忽略了lastTransaction成员变量
return *this;
}
上述代码的问题很明显,就是没有拷贝lastTransaction成员变量,更为严重的是,编译器并不会提醒你这个错误。
结论就是,如果为class添加一个成员变量,必须同时修改copying函数(包括拷贝构造函数和重载赋值操作符)

如果发生了继承,会带来什么样的危险呢?
class PriorityCustomer: public Custoer {
public:
...
PriorityCustomer(const PriorityCustoer& rhs);
PriorityCustomer& operato=(const PriorityCustomer& rhs);
...
private:
int priority;
}; PriorityCustomer&
PriorityCustomer::PriorityCustomer (const PriorityCustomer& rhs)
: priority(rhs.priority)
{
logCall("PriorityCustoer copy constructor");
} PriorityCustomer&
PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
logCall("PriorityCustomer copy assignment operator");
priority = rhs.priority;
return *this;
}

问题:

PriorityCustomer的拷贝函数们拷贝了它声明的成员变量,却忽略了它所继承的Customer成员变量的拷贝,也没有指定实参传递给Customer的构造函数,因此,PriorityCustomer对象的Customer成分会被不带实参的Customer默认构造函数初始化。

改进:为子类编写拷贝函数时,必须要复制其基类部分。
PriorityCustomer&
PriorityCustomer::PriorityCustomer (const PriorityCustomer& rhs)
: Customer(rsh), priority(rhs.priority)
{
logCall("PriorityCustoer copy constructor");
} PriorityCustomer&
PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
logCall("PriorityCustomer copy assignment operator");
Customer::operator=(rhs);
priority = rhs.priority;
return *this;
}

结论

确保赋值所有local成员变量

调用所有base classes内的适当的拷贝函数

需要注意的一点是:
虽然重载赋值操作符和拷贝函数的代码长得很像,但是很难复用它们,因为重载赋值操作符时调用拷贝构造函数就像在构造一个已经存在的对象;
同样地,令拷贝构造函数调用重载赋值操作符一样没有意义。

所以,复用这两个代码的方式就是写一个新的成员函数给两者调用。

小结:
拷贝构造函数和重载赋值操作符应该确保复制“对象内的所有成员变量”及“所有base class成分”;
不要尝试拷贝构造函数调用重载赋值操作符或是反过来。
参考资料:
《Effective C++ 3rd》

Effective C++(12) 复制对象时要复制每一个成员的更多相关文章

  1. Effective C++ 条款11,12 在operator= 中处理“自我赋值” || 复制对象时不要忘记每一个成分

    1.潜在的自我赋值     a[i] = a[j];     *px = *py; 当两个对象来自同一个继承体系时,他们甚至不需要声明为相同类型就可能造成别名. 现在担心的问题是:假如指向同一个对象, ...

  2. EC笔记:第二部分:12、复制对象时勿忘其每一个成分

    EC笔记:第二部分:12.复制对象时勿忘其每一个成分 1.场景 某些时候,我们不想使用编译器提供的默认拷贝函数(包括拷贝构造函数和赋值运算符),考虑以下类定义: 代码1: class Point{ p ...

  3. Effective C++ -----条款12: 复制对象时勿忘其每一个成分

    Copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”. 不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两个cop ...

  4. Effective C++ 条款12:复制对象时勿忘其每一个成分

    void logCall(const std::string& funcName); class Customer { public: ... Customer (const Customer ...

  5. Effective C++_笔记_条款12_复制对象时勿忘其每一个成分

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 编译器会在必要时候为我们的classes创建copying函数, ...

  6. [Effective C++ --012]复制对象时勿忘其每一个成分

    引言: 在深拷贝和浅拷贝的理解中,我们知道了“拷贝构造函数”一词,并且也了解了它的构成. A(const A& r); // 形式有多种,在这里只列出一个 因此,在值传递的应用场景里,我们可以 ...

  7. EC读书笔记系列之7:条款12 复制对象时勿忘其每一个成分

    记住: ★copying函数应确保复制“对象内的所有成员变量”及“所有base class成分” ★不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两 ...

  8. 条款12:复制对象时勿忘其每一个成分(Copy all parts of an object)

    NOTE: 1.Copying 函数应该确保复制“对象内的所有成员变量”及“所有base class成分”. 2.不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个 ...

  9. C++复制对象时勿忘每一部分

    现看这样一个程序: void logCall(const string& funcname) //标记记录 { cout <<funcname <<endl; } cl ...

随机推荐

  1. Service与Activity与交流AIDL

    深圳旅游月.终于回来了,做了很多个月,这些天来的东西会慢慢总结出来的.今天,我们正在谈论的Service小东西:沟通. 固定通信的做法比较,基本上按照写模板可以实现. 1.Service与Activi ...

  2. Android变化如何破解几场金

    我们在玩游戏的总会遇到一些东西需要购买,但是,我们可能要花钱,那么我们应该怎么办呢?这与游戏的插.我们在这里谈论的Android游戏,搜索互联网上的移动端游戏插件,您可能会发现一个叫段:八门神器.ap ...

  3. Centos7系统配置上的变化(三)为网络接口添加多IP

    原文 Centos7系统配置上的变化(三)为网络接口添加多IP 实验的方法有 nmtui, 编辑ifcfg-*文件,ip addr 指令,子连接配置文件.一.nmtui手工添加IP 看一下当前网络设备 ...

  4. iphone手机版降级

    想减少移动版本号.你能下载下来你想要的版本在苹果开发者网站,或"信誉"或可以下载到其他网站的iPhone下载固件固件网站.然后打开iTunes,进入 然后按着(alt).同一时候用 ...

  5. Session与Caching

    Session与Caching 在之前的版本中,Session存在于System.Web中,新版ASP.NET 5中由于不在依赖于System.Web.dll库了,所以相应的,Session也就成了A ...

  6. 深入浅出MS06-040

    入浅出MS06-040 时至今日,网上已有颇多MS06-040的文章,当中不乏精辟之作.与其相比,本文突显业余,技术上无法超越,徒逞口舌之快.本文适合有一定计算机基础,初步了解溢出攻击原理,略微了解逆 ...

  7. yii 使用 mongodb 小工具 YiiMongoDbSuite

    YiiMongoDbSuite下载链接: http://www.yiiframework.com/extension/yiimongodbsuite/ 如果你的yii和mongodb它已经建立了一个良 ...

  8. js小记 function 的 length 属性

    原文:js小记 function 的 length 属性 [1,2,3]., ,这个略懂js的都知道. 但是  eval.length,RegExp.length,"".toStr ...

  9. PHP採集CSDN博客边栏的阅读排行

    项目中要用到採集的数据,所以就先拿CSDN博客来试了试.这里使用Simple HTML DOM(官网)这个库,它可以方便的遍历HTML文档. <?php include_once('simple ...

  10. 让Docker功能更强大的10个开源工具

    让Docker功能更强大的10个开源工具 更好的管理.Web前端程序.更深入地了解容器应用程序,Docker生态系统正在迅速发展,这还得归功于其充满活力的开源社区. 软件项目的成功常常根据其催生的生态 ...