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

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. .net下几种常用的对称加解密

    加密解密算法,太常用了,可是实在忍受不了十次八次之后还是要重头写,总是能告诉我原来的算法不好用(实际是压根不会用)的情况,不如直接写出来,再有人要直接给他看看,也顺便记录下算法,方便下新手大众. DE ...

  2. OCP读书笔记(23) - 题库(ExamC)

    200.Which operation requires that you create an auxiliary instance manually before executing the ope ...

  3. java线 生产者和消费者

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGlhbmdydWkxOTg4/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  4. java_Eclipse主题颜色配置+全屏

    http://www.eclipsecolorthemes.org/ 这个是主题的网站. 在Eclipse里, File->Import->General->Preferences- ...

  5. android 数据共享

    android数据共享的各种部件中的应用是最重要的3途径: 第一.使用Application子类来实现数据共享. 例如,请看下面的例子: /**  * @author YangQuanqing 特征: ...

  6. poj 1679 The Unique MST 【次小生成树】【模板】

    题目:poj 1679 The Unique MST 题意:给你一颗树,让你求最小生成树和次小生成树值是否相等. 分析:这个题目关键在于求解次小生成树. 方法是,依次枚举不在最小生成树上的边,然后加入 ...

  7. OWIN– 解耦,协作和开放

    OWIN的理解和实践(一) – 解耦,协作和开放 概述 OWIN的全称是Open Web Interface For .Net, 是MS在VS2013期间引入的全新的概念, 网上已经有不少的关于它的信 ...

  8. JS正则替换字符串

    1.只替换第一次出现的字符: text.replace(/javascript/i, "JavaScript");  //正则用//来将正则包起来 i表示区分大小写 2.全局替换: ...

  9. Android 2.3 版本中链接边框问题解决

    在做移动互联网开发的过程中,同样需要考虑到移动终端(如手机.平板)的不同版本浏览器兼容问题,在Android 2.3 版本的默认浏览器中有一个bug-会自动给所有链接文本在点击操作过程中加黄色或绿色边 ...

  10. Windows下C语言的Socket编程例子(TCP和UDP)

    原文:Windows下C语言的Socket编程例子(TCP和UDP) 刚刚学windows编程,所以想写学习笔记,这是一个简单的Socket程序例子,开发环境是vc6: 首先是TCP server端: ...