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

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. Python基本语法[二],python入门到精通[四] (转)

    写在前面 python你不去认识它,可能没什么,一旦你认识了它,你就会爱上它 回到顶部 v正文开始:Python基本语法 1.定义常量: 之所以上篇博客介绍了定义变量没有一起介绍定义常量,是因为Pyt ...

  2. swift 笔记 (七) —— 关闭

    关闭 封闭件是从包括以下各项的组.它可以在代码被发送"片"... 行,不纠结的定义.继续. swift的闭包,有点像C和Objective-C语言里的 代码块 {--}  闭包能够 ...

  3. 1第一个Android应用程序

    第一个程序从 Hello World 開始?? 或许C语言学习是从这開始的,可是书上不是这么開始的,或许起点就决定了高度?? 一.新建安卓项目 (1)选择安卓项目 (2)随便建个名字的项目,默认下一步 ...

  4. [ZZ] python 语言技巧

    http://sahandsaba.com/thirty-python-language-features-and-tricks-you-may-not-know.html  感谢原作者 30 Pyt ...

  5. 《高性能 JavaScript》读书笔记(一)

    一. 加载和执行——优化JavaScript规则: 1. 将脚本放在底部:2. 减少页面中外链脚本文件的数量: 比如,下载单个100kb的文件将比下载4个25kb的文件更快.这个可以通过离线打包工具或 ...

  6. 《STL源代码分析》---stl_list.h读书笔记

    STL在列表list它是一种经常使用的容器.list不连续双向链表在内存,而且是环形. 理解列表如何操作的详细信息,然后.阅读STL名单上的代码是最好的方法. G++ 2.91.57.cygnus\c ...

  7. oracle_体系结构图_逻辑结构图

    1.oracle 的体系结构图  重要!!! 2.oracle的逻辑结构图

  8. 【百度地图API】如何获取行政区域的边界?

    原文:[百度地图API]如何获取行政区域的边界? 摘要:以前教过大家如何自行获取行政区域,或者自定义获取一个区域的边界值.今天来教大家直接调用百度地图API1.3(目前最新版本)来获取行政区域的边界值 ...

  9. 深入理解C指针之五:指针和字符串

    原文:深入理解C指针之五:指针和字符串 基础概念 字符串可以分配到内存的不同区域,通常使用指针来支持字符串操作.字符串是以ASCII字符NUL结尾的字符序列.ASCII字符NUL表示为\0.字符串通常 ...

  10. asp.net 操作XML

    using System.Xml; using System.Data; using System.IO;   string xmlpath = HttpRuntime.AppDomainAppPat ...