C++ 复制控制之复制构造函数

C++类用三个特殊的成员函数:复制构造函数、赋值操作符和析构函数 来决定类对象之间的初始化或赋值时发生什么。所谓的"复制控制"即通过这三个成员函数控制对象复制的过程

复制构造函数首先是一个构造函数,它同所有其他的构造函数一样与类同名,没有返回值。它有一个唯一的参数(错误),是该类类型的引用(一般将它声明为const,源于用于赋值的对象一般不用改变它本身的值)。于是复制构造函数的原型为:

cpp 复制代码
class BOOK
{
    public:
     BOOK(const BOOK& rhs); //构造函数一
     BOOK(string &name,float price = 0):_bookName(name),_price(price){}; //构造函数二
     BOOK():_price(0),_bookName(""){}; //构造函数三

  private:
     float _price ;
     string _bookName;
  //....
};

什么时候被调用

复制构造函数在需要复制类对象的时候被调用,这些调用情况可以总结为:

根据一个同类型的对象显示或隐式地初始化一个对象。

1.当定义一个新对象并用一个同类型的对象对它进行初始化的时候,将显式使用复制构造函数,如:

cpp 复制代码
BOOK book1;
BOOK book2(book1);

当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式地调用复制构造函数。

1.作为值传递的实参传递给一个函数。

2.函数返回时复制一个对象。

3.初始化顺序容器中的元素。

如:

cpp 复制代码
vector<string> svec(5);

编译器首先调用string类默认构造函数创建一个临时值,再用复制构造函数将临时值复制到每一个元素。

1.根据元素初始化列表初始化数组元素。

如:

cpp 复制代码
BOOK books[]={
  string("book1"),
  string("book2"),
  string("book3"),
  BOOK()
};

book数组的前三个元素将调用构造函数二进行隐式类型转换(C++隐式类型转换),然后调用复制构造函数进行数组元素的复制。如果类禁止隐式类型转换(构造函数使用了explicit声明),或希望不指定实参或多个实参,需要使用完整的构造函数语法,如数组最后一个元素的初始化。

如果没有为类声明复制构造函数会怎样

如果你没有声明一个复制构造函数,那么编译器会给声明一个。实际上,如果你自己没有声明,编译器会为类声明一个复制构造函数 ,一个赋值操作符以及一个析构函数,此外如果你没有声明任何构造函数的话,编译器也会为你声明一个合成默认构造函数。(错误)所有这些编译器自动生成的类成员函数皆为pubilc 且 inline。编译器创建的复制构造函数单纯地将来源对象的每一个非static成员拷贝到目标对象,这在很多时候是不能满足类需求的,特别是类中含有指针时,这时候就需要我们自己来写复制控制的三个特殊成员函数了。

编译器合成的复制构造函数做了什么

合成复制构造函数的行为是:对每一个非static成员进行逐个成员初始化。成员类型不同,初始化方式不一样:

内置类型(如int):直接复制值。

类类型:调用该类的复制构造函数进行复制。

数组:这个比较特殊,因为我们知道一般不能复制数组,但在类中,复制数组时合成复制构造函数将复制数组的每一个值。

另外,合成复制构造函数对类数据成员的初始化都是放在构造函数初始化列表中进行的。

禁止复制

如果我们想禁止某个类的复制行为,我们当然不会想去定义一个复制构造函数,然而编译器却会自动为我们定义一个,那么到底该如何阻止一个类的复制行为呢?

我们可以将复制构造函数定义为private,不允许用户代码复制该类类型的对象,若进行复制将在编译时发生错误。然而类的友元和成员仍可以进行复制,解决办法是我们可以声明一个private复制构造函数却不进行定义,类成员或友元进行复制尝试时,将在程序运行时发生错误。


推荐一个零声学院项目课,个人觉得老师讲得不错,分享给大家:
零声白金学习卡(含基础架构/高性能存储/golang云原生/音视频/Linux内核)
https://xxetb.xet.tech/s/3Zqhgt

相关推荐
七七&5561 小时前
2024年08月13日 Go生态洞察:Go 1.23 发布与全面深度解读
开发语言·网络·golang
java坤坤1 小时前
GoLand 项目从 0 到 1:第八天 ——GORM 命名策略陷阱与 Go 项目启动慢问题攻坚
开发语言·后端·golang
元清加油1 小时前
【Golang】:函数和包
服务器·开发语言·网络·后端·网络协议·golang
健康平安的活着2 小时前
java之 junit4单元测试Mockito的使用
java·开发语言·单元测试
No0d1es2 小时前
电子学会青少年软件编程(C/C++)5级等级考试真题试卷(2024年6月)
c语言·c++·算法·青少年编程·电子学会·五级
DjangoJason3 小时前
C++ 仿RabbitMQ实现消息队列项目
开发语言·c++·rabbitmq
m0_480502644 小时前
Rust 入门 KV存储HashMap (十七)
java·开发语言·rust
大阳1234 小时前
线程(基本概念和相关命令)
开发语言·数据结构·经验分享·算法·线程·学习经验
YA3334 小时前
java基础(九)sql基础及索引
java·开发语言·sql
奇树谦5 小时前
QT|windwos桌面端应用程序开发,当连接多个显示器的时候,如何获取屏幕编号?
开发语言·qt