C++-copy constructor、copy-assignment operator、destructor

本文探讨C++中复制构造函数、复制赋值运算符及析构函数的基本概念、触发时机及其默认行为。深入剖析如何自定义这些成员函数以满足特定需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文由@呆代待殆原创,转载请注明出处。

 

对于一个类来说,我们把copy constructor、copy-assignment operator、move constructor、move-assignment operator、destructor统称为copy control。

今天我们先来聊聊其中的copy constructor、copy-assignment operator的destructor这三个。

 

copy constructor

copy constructor:一个constructor如果他的第一个参数是对类的引用,且其他的参数都有缺省值(default values)则,这是一个copy constructor。

1,第一个参数必须是引用类型,因为当我们把一个object当做参数传递给一个方法的非引用变量的时候会自动调用copy constructor方法,如果copy constructor自身的参数就是非引用类型的话,这个方法就会引起无限递归调用,然后你的程序就boomshakalaka~~。

2,一般我们会把第一个参数设成const,因为一般情况下不会对其进行修改,除非你另有打算。

3,因为copy constructor在很多情况下是默认调用的,如以下情况,所以一般不会把copy constructor设成explicit。

1 std::string s;
2 std::string s1 = s; //隐式调用了copy constructor
3 std::string s2 = std::string(s1);//显式调用了copy constructor

 

1 class Foo{
2 public:
3     Foo(const Foo&);
4     //...
5 };

何时发生copy constructor调用

为了弄清这个问题我们需要弄清另外一组概念:direct initialization 和copy initialization。

direct initialization:要求编译器按照一般的方法匹配(function matching)来选择要调用的方法。

copy initialization:要求编译器将右操作数拷贝到左操作数,有必要的话还会进行类型转换,这个过程会调用copy constructor或者move constructor(本文暂不介绍)。

1 std::string s1("balabala");                       //direct initialization
2 std::string s2(10, 'a');                          //direct initialization
3 std::string s3 = s2;                              //copy initialization
4 std::string s4 = std::string(s3);                 //copy initialization
5 std::string s5 = "const char* converts to string";//copy initialization

 copy initialization发生的情况如下:

1,用=来初始化定义的变量时。

2,把一个object当做参数传递给一个方法的非引用变量的时。

3,方法返回一个非引用类型的object时。(返回时会首先生成一个临时object)

4,用花括号列表初始化一个数组或聚合类(aggregate class)成员时。

由于编译器带来的误解:

现在的编译器有时候会自动绕过copy constructor即编译器会把下面这一句话

 std::Book book = "9-9-9-9";//假设Book是一个自定义的类 

换成下面这个

 std::Book book("9-9-9-9"); 

请注意在执行上上面两句语言是完全不一样的,第一句会首先调用Book(const char*)构造函数生成一个临时object然后再调用Book(const Book&)把临时object复制给book。而第二句话会直接调用Book(const char*)然后完事儿。如果你想验证他们的区别可以实现Book类并将Book(const Book&)设置成私有方法(防止编译器自动优化),之后你就会发现第一条语句无法执行了。

 

Copy-assignment operator

copy-assignment operator:写这个方法就是对=操作符进行重载。

1,copy-assignment operator的返回值一般是对其左操作数(left-hand operand)的引用,这是为了让object的行为更像内置类型而决定的。

1 class Foo{
2 public:
3     Foo& operator=(const Foo&);
4     //...
5 };

何时发生copy-assignment operator调用

答案很显然是用到=操作符的时候啊,但是这里要注意的是

初始化的时候并不会调用copy-assignment operator

初始化的时候并不会调用copy-assignment operator

初始化的时候并不会调用copy-assignment operator

重要的事情说三遍,举例如下

1 std::string s;
2 std::string s1 = s;    //对s1进行初始化,调用的是copy constructor
3 s1 = s;                //对s1进行赋值,调用的是copy-assignment operator

 

 Destructor

Destructor:destructor有两个部分,function body和destruction part,前者由类的编写者写明需要做的内容,后者是隐式的,不需要程序员关心,在function body执行完后自动执行,会销毁类的非静态数据成员。

1,因为Destructor没有参数,所以它是不能被重载的

1 class Foo{
2 public:
3     ~Foo();
4     //...
5 };

何时发生Destructor调用

1,当超出object 的作用域(scope)时。

2,容器销毁时(container),里面的元素(element)也会跟着调用自身的destructor从而销毁。

3,人为使用delete的时候。

4,由某个表达式创建的临时变量在这个表达式执行完后将自动调用destructor从而销毁。

5,类的成员如果自身有destructor,会在这个类销毁的时候调用自身的destructor。

 

 关于编译器自动提供的版本(Synthesized)

Synthesized copy constructor:即使我们提供了其他版本的copy constructor,编译器仍然会提供这个版本的copy constructor给我们,它会依次复制非静态成员给被创建的object,对数组也能正常工作,对于class类型会调用它们自己的copy constructor。

Synthesized copy-assignment operator:行为和Synthesized copy constructor类似,依次把非静态成员复制给左操作数。

Synthesized destructor:destructor的function body为空。

 

 关于何时我们需要自定义上述的三个方法

1,当需要destructor时,上述三给方法都是需要的。

2,当需要copy constructor时,copy-assignment operator也是需要的,反之亦然。

而当我们需要删除自己动态分配的内存时,就要用到destructor。

当我们需要进行深度复制时会用到另外两个,比如对指针指向的元素进行复制等等。

 

关于delete和default的用法

我们可以用default显示声明我们想要用默认版本的copy control,也可以用delete显示声明我们完全不需要这类方法来达到禁止这个object进行相关的复制和赋值操作。

1,我们能delete除了destructor以外的所有方法来达到显示告知这个object不能进行相关操作的目的,delete只能写在一次声明出现的地方。

2,我们能对所有有默认版本的函数用default显示声明我们需要这个默认版本,default可以写在方法声明的地方也可以写在方法定义的地方。

1 class Foo{
2 public:
3     Foo() = default;                     //显式说明使用默认版本
4     Foo(const Foo&) = delete;            //delete copy constructor
5     Foo& operator=(const Foo&) = delete; //delete copy-assignment operator
6     ~Foo() = default;                    //显式说明使用默认版本
7     void myFuntion() = delete;           //delete自己的方法
8     //...
9 };

 

 

参考资料:《C++ primer 英文第五版》

转载于:https://www.cnblogs.com/coffeeSS/p/5398859.html

C++ defines a class DateV3 with the following: private member variables: int year, month, day; Has three constructors and one destructor as follows: The first constructor takes three parameters, int y, int m, int n; The second is the copy constructor that takes a DateV3 object as the parameter; The third is the default constructor that takes no parameter; The destructor takes no parameter. (3) Has overloaded operators: int operator-(DateV3 & oneDate); // return difference in days between the calling object and oneDate DateV3 operator+(int inc); // return a Date object that is inc days later than the calling object DateV3 operator-(int dec); // return a Date object that is dec days earlier than the calling object DateV3 operator++(); // overload the prefix ++ operator DateV3 operator++(int); // overload the postfix ++ operator friend ostream& operator<< (ostream& outputStream, DateV3& theDate); // overload the << operator Test class DateV3 in the main function as follows: Declare and initialize an object to represent today, which should be the date that you work on this assignment.Declare and initialize an object to represent your OWN birthday.Express John’s birthday given John is 5 days older than yours. Create Tom’s birthday by using the copy constructor, assuming Tom has the same birthday as you. Display how many days have passed since your birth, John’s birth, and Tom’s birth, respectively. Create an DateV3 object, someday, by cloning Tom’s birthday. Increment someday by the prefix operator ++ once, and by postfix operator ++ once.Display someday, today, your birthday, John’s birthday, and Tom’s birthday. Declare a DateV3 object to represent 28 February 2024, display it, apply the prefix ++ operator on it, display it again, and apply the postfix ++ operator on it and display it again.
06-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值