当前位置: 首页 > news >正文

item12-- 拷贝一个对象的所有组成部分

当你决定不使用编译器自动生成的拷贝构造函数(Copy Constructor)和拷贝赋值操作符(Copy Assignment Operator),而是自己重写它们时,编译器就会“洗手不管”了。它会假设你完全知道自己在做什么,如果你漏掉了某些数据成员,编译器不会报错,这就会导致“局部拷贝”(Partial Copy)的风险。


1. 陷阱一:新增成员变量时忘记更新

这是最容易发生的错误。当你的类随着开发过程不断演进,增加了一个新的成员变量,但你忘记了更新 copying 函数。

场景: 你有一个 Customer 类,后来你加了一个 lastTransaction 字段。

class Customer {
public:Customer(const Customer& rhs) : name(rhs.name) // 复制了 name// 哎呀!忘记复制 lastTransaction 了!{ }Customer& operator=(const Customer& rhs) {name = rhs.name; // 复制了 name// 哎呀!又忘记 lastTransaction 了!return *this;}
private:std::string name;Date lastTransaction; // 新增变量
};

后果: 编译器完全不会警告你。你的对象会被复制,但 lastTransaction 字段要么是默认值,要么是未定义的,而不是原对象的拷贝。


2. 陷阱二:继承体系中的“切片” (The Bigger Trap)

这是 Item 12 强调的重难点。当你为派生类(Derived Class)编写 copying 函数时,很容易只复制派生类自己的成员,而忘记了复制基类(Base Class)的成员。

错误的示范:

class PriorityCustomer : public Customer {
public:// 拷贝构造函数PriorityCustomer(const PriorityCustomer& rhs): priority(rhs.priority) // 只复制了自己的成员{// 这里的 Customer 部分发生了什么?// 答:调用了 Customer 的"默认构造函数"(Default Constructor)!// 并没有从 rhs 那里复制 Customer 的数据!}// 赋值操作符PriorityCustomer& operator=(const PriorityCustomer& rhs) {priority = rhs.priority; // 只复制了自己的成员return *this;// 基类的数据成员没有改变!}private:int priority;
};

发生了什么? 在拷贝构造函数中,如果你不显式调用基类的拷贝构造函数,编译器会自动调用基类的默认构造函数。这意味着新对象的基类部分被“重置”了,而不是被“复制”了。


3. 正确的写法:显式调用基类的 Copy 函数

你必须在派生类的 copying 函数中,显式地处理基类部分。

正确的示范:

class PriorityCustomer : public Customer {
public:// 1. 正确的拷贝构造函数PriorityCustomer(const PriorityCustomer& rhs): Customer(rhs), // 【关键】显式调用基类的拷贝构造函数priority(rhs.priority){ // LogCall("Copy Constructor"); }// 2. 正确的赋值操作符PriorityCustomer& operator=(const PriorityCustomer& rhs) {// LogCall("Copy Assignment Operator");Customer::operator=(rhs); // 【关键】显式调用基类的赋值操作符priority = rhs.priority;return *this;}
private:int priority;
};

4. 不要尝试“互相调用”

虽然拷贝构造函数和赋值操作符的代码往往很像(都是复制成员),但绝对不要尝试用一个调用另一个:

  • 不要在 operator= 中调用 Copy Constructor: 构造函数是用来初始化未存在的对象的,而赋值是对已存在对象操作,这在逻辑和底层内存处理上都是错的。
  • 不要在 Copy Constructor 中调用 operator= 此时对象还在初始化过程中,对象尚未构造完整,调用赋值操作符是不安全的。

解决方案: 如果代码重复太多,建立一个私有的 void init() 函数,让两者都去调用它。


总结 (Takeaway)

当你自己编写 Copying 函数(拷贝构造函数 或 赋值操作符)时,请务必检查以下两点:

  1. 复制所有的 local 成员变量: 每次新增成员变量,都要记得更新这两个函数。
  2. 调用所有的 base class 的对应函数: 在派生类中,务必显式调用基类的 copy 构造函数或 operator=
http://www.jsqmd.com/news/115938/

相关文章:

  • sub_match
  • sub_match
  • 抽奖机随机号码生成:3 种算法实现 + 测试全解析(附完整代码)
  • 【零基础精通】Python 字符串全解析:从字符序列到不可变对象的深度构建
  • item14--谨慎考虑资源管理类的拷贝行为
  • python django flask酒店客房管理系统数据可视化分析系统_gq8885n3--论文md5
  • python django flask鹿幸公司员工食堂在线点餐餐饮餐桌预约管理系统的设计与实现_utcnqqs0--论文
  • error_code
  • 虚拟化初步了解
  • Miloco 深度打通 Home Assistant,实现设备级精准控制
  • 好用的大型牛场水滴粉碎机技术强的
  • set_value
  • 日记1217
  • function的类型擦除
  • function bind
  • 日记12,19
  • Item10--令赋值操作符返回一个
  • Item9--绝不在构造和析构过程中调用虚函数
  • python django flask考研互助交流平台_c62p51fu--论文
  • 日记12.18
  • 离散化遍历
  • Ubuntu上使用VScode创建Maven项目
  • 线程(2)
  • 大规模语言模型的抽象思维与创新能力培养
  • 线程(1)
  • 方达炬〖发明超新技术〗:冰堆技术;冷极冰堆建筑技术;
  • Item6--若不想使用编译器自动生成的函数,就该明确拒绝
  • 我发现LLM解析基因数据优化抗癌药剂量,患者副作用直降40%
  • 日记12.16
  • 论文AIGC查重率高怎么办?6个降AI率工具和技巧,AI率从100%降到3%! - 还在做实验的师兄