Item 12:完整地拷贝对象(拷贝构造函数、复制运算符) Effective C++笔记

Item 12: Copy all parts of an object

在一个成熟的面向对象的C++系统中,只有两种拷贝对象的方式:复制构造函数和赋值运算符, 不妨称他们为拷贝函数。 拷贝函数属于编译器默认生成的函数(参考:Item
5:那些被C++默默地声明和调用的函数
), 默认的拷贝函数确实会完整地拷贝对象,但有时我们选择重载拷贝函数,问题就出在这里!

一个正确拷贝函数的实现是这样的:

class Customer{
  string name;
public:
  Customer::Customer(const Customer& rhs): name(rhs.name){}
  Customer& Customer::operator=(const Customer& rhs){
    name = rhs.name;                     // copy rhs‘s data
    return *this;                        // see Item 10
  }
};

很完美对吧?但是有一天你新添加了一个数据成员,但忘记了更新拷贝函数:

class Customer{
  string name;
  Date lastTransaction;
public:
  Customer::Customer(const Customer& rhs): name(rhs.name){}
  Customer& Customer::operator=(const Customer& rhs){
    name = rhs.name;                     // copy rhs‘s data
    return *this;                        // see Item 10
  }
};

这时lastTransaction便被被你忽略了,编译器也不会给出任何警告(即使在最高警告级别)。
另外一个常见的情形在你继承父类时:

class PriorityCustomer: public Customer {
int priority;
public:
  PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
  : priority(rhs.priority){}

  PriorityCustomer&
  PriorityCustomer::operator=(const PriorityCustomer& rhs){
    priority = rhs.priority;
  }
};

上述代码看起来没有问题,但你忘记了拷贝父类的部分:

class PriorityCustomer: public Customer {
int priority;
public:
  PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
  : Customer(rhs), priority(rhs.priority){}

  PriorityCustomer&
  PriorityCustomer::operator=(const PriorityCustomer& rhs){
    Customer::operator=(rhs);
    priority = rhs.priority;
  }
};

总之当你实现拷贝函数时,

  • 首先要完整复制当前对象的数据(local data);
  • 调用所有父类中对应的拷贝函数。

你可能注意到了代码的重复,但千万不要让复制构造函数和赋值运算符相互调用,它们的语义完全不同! C++甚至都没有提供一种语法可以让赋值运算符调用复制构造函数;反过来让复制构造函数调用赋值运算符倒是可以编译, 但由于复制构造函数的前置条件是一个未初始化的对象,而赋值运算符的前置条件是一个已初始化的对象。 这样的调用并非好的设计,恐怕会引起逻辑混乱。

但是代码重复怎么办?Scott Meyers提出可以抽象到一个普通方法中,比如init。是不是联想到了Objective-C的init函数?



除非注明,本博客文章均为原创,转载请以链接形式标明本文地址: http://harttle.com/2015/08/01/effective-cpp-12.html

版权声明:本文为博主原创文章,转载请附上原文链接。

时间: 2024-10-11 12:42:54

Item 12:完整地拷贝对象(拷贝构造函数、复制运算符) Effective C++笔记的相关文章

Item 17:在单独的语句中将new的对象放入智能指针 Effective C++笔记

Item 17: Store newed objects in smart pointers in standalone statements. 在单独的语句中将new的对象放入智能指针,这是为了由于其他表达式抛出异常而导致的资源泄漏. 因为C++不同于其他语言,函数参数的计算顺序很大程度上决定于编译器. 如果你在做Windows程序设计,或者DLL开发,可能会经常碰到类似__cdecl,__stdcall等关键字.它们便是来指定参数入栈顺序的. 关于函数和参数的讨论可以参考:C++手稿:函数与

ES6扩展运算符(三点运算符)“...”用法和对象拷贝

es6拷贝数组对象有以下方法: 方法一: Object.assign() // 对象浅拷贝,obj1复制给obj2,这种方法要把obj2设置为{},不能const obj2 = ""; const obj1 = {a: 1}; const obj2 = {}; Object.assign( obj2, obj1) 方法二 :ES6扩展运算符(...) //对象浅拷贝,obj1复制给obj2 const obj1 = {a: 1}; const obj2 = {...obj1}; 方法三

读书笔记 effective c++ Item 14 对资源管理类的拷贝行为要谨慎

1. 自己实现一个资源管理类 Item 13中介绍了 “资源获取之时也是初始化之时(RAII)”的概念,这个概念被当作资源管理类的“脊柱“,也描述了auto_ptr和tr1::shared_ptr是如何用堆资源来表现这个概念的.然而并不是所有资源都是在堆上创建的,对于这种资源,像auto_ptr和tr1::shared_ptr这样的智能指针就不适合当作资源句柄(handle)来使用了.你会发现你时不时的就会需要创建自己的资源管理类. 举个例子,假设你正在使用C API来操纵Mutex类型的互斥信

OC中对象拷贝概念

OC中的对象拷贝概念,这个对于面向对象语言中都会有这种的问题,只是不同的语言有不同的解决方式:C++中有拷贝构造函数,Java中需要实现Cloneable接口,在clone方法中进行操作.但是不过OC更偏向于Java这种方式,OC中如果一个对象需要被拷贝,他需要实现协议:<NSCopying>.<NSMutableCopying>从名字上我们可以看到,一个协议是用于不可变对象的,一个协议适用于可变对象的 首先来介绍一下对象的拷贝的概念吧:为什么要由对象的拷贝这么一个概念呢?看一个场

Java 对象拷贝答疑

Java 对象拷贝答疑 @author ixenos 关于clone[对象拷贝] 在实际编程过程,有时候我们会遇到一种情况:当你有一个对象A,在某一个时刻,A已经保存了对应的属性值,而且这些值本身是有效的,这个时候可能需要一个和A完全相同的对象B,并且当B里面的属性值发生变化的时候,A中的属性值不受影响,可以理解为A和B独立,但是B的初始化不是按照我们平时创建该对象的时候的初始化操作,B的初始化数据完全来自A. 对Java存储模型了解的人都明白,在Java里面如果针对两个对象引用采取赋值操作的时

Java 开发中的对象拷贝

前言 在 Java 开发中,很多时候需要将两个属性基本相同的对象进行属性复制,比如 DO 转 VO等等. 本文主要介绍自己实现的简易拷贝工具类与 Spring 提供的属性拷贝的对比. Spring 提供的属性拷贝 在 Spring 中直接调用 BeanUtils.copyProperties();即可. 它的核心通过循环 target 的所有方法名,然后在 source 中找到对应的方法名,最后通过反射从 source 中获取并写入 target 中. Spring 没有通过 java.lang

Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)

http://www.jb51.net/article/15714.htm 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象.2. copy.deepcopy 深拷贝 拷贝对象及其子对象 一个很好的例子: 1 import copy 2 a = [1, 2, 3, 4, ['a', 'b']] #原始对象 3 4 b = a #赋值,传对象的引用 5 c = copy.copy(a) #对象拷贝,浅拷贝 6 d = copy.deepcopy(a) #对象拷贝,深拷贝

Objective-C:OC内部可变对象和不可变对象的深(复制)拷贝问题思考:

OC内部:可变对象和不可变对象的深(复制)拷贝问题思考: 不可变对象: 例如NSString对象,因为NSString对象是常量字符串,所以,不可以更改其内容,但是可以修改指向该字符串的指针指向.当对NSString对象做深拷贝时,如果是copy复制方式,其实就是浅复制,只是复制了同一个对象的指针:如果是mutableCopy复制方式,系统会分配一个新的内存空间用来存放复制出来的NSMutableString对象,此时地址是新的,内容是一样的,他们正在被不同的实例变量字符串指针指着. 可变对象:

Javascript对象拷贝(clone)

1. [代码]方法代码     function cp(source, target) {    function isBaseType(v) {        var type = typeof v;        var basetype = {            "string": true,            "number": true,            "boolean": true,            "