C++ 拷贝构造函数和赋值运算符

  这篇文章主要介绍拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数,什么情况下调用赋值运算符。    

  拷贝构造函数和赋值运算符

  在默认情况下(用户没有定义,但是也没有显示的删除),编译器会自动隐式生成一个拷贝构造函数和赋值运算符,但用户可以使用delete来指定不生成拷贝构造函数和赋值运算符,这样的对象就不能通过值传递,也不能进行赋值运算

 1 #include <iostream>
 2
 3 using namespace std;
 4 class Person {
 5 public:
 6     Person():{}
 7     Person(const Person& p) = delete;
 8     Person& operator= (const Person& p) = delete;
 9
10     void SetName( string  strName )
11     {
12         name = strName;
13     }
14     void SetAge(int nAge)
15     {
16         age = nAge;
17     }
18 private:
19     int age;
20     string name;
21 };
22 int main()
23 {
24     Person p1;
25     p1.SetName("air");
26     p1.SetAge(18);
27
28     //Person p2(p1);   错误的
29     return 0;
30 }

上面定义的类Person显式的删除了拷贝构造函数和赋值运算符,在需要调用拷贝构造函数或者赋值运算符的地方,会提示无法调用该函数,它是已删除的函数。

还有一点需要注意的是,拷贝构造函数必须以引用的方式传递参数,这是因为,在值传递给一个函数的时候,会调用拷贝构造函数生成函数的实参,如果拷贝构造函数的参数仍然是以值的方式,就会无限循环的调用下去,直到函数的栈溢出。

何时调用

  拷贝构造函数和赋值运算符的行为比较相似,都是将一个对象的值复制给另一个对象,但是其结果却有些不同,拷贝构造函数使用传入对象的值生成一个新的对象的实例,而赋值运算符是将对象的值复制给一个已经存在的实例。这种区别从两者的名字也能轻易的分辨出来,拷贝构造函数也是一种构造函数,那么它的功能就是创建一个新的对象实例;赋值运算符是执行某种运算,将一个对象的值复制给另一个对象(已经存在的)。调用的是拷贝构造函数还是赋值运算符,主要是看是否有新的对象实例产生,如果产生了新的对象实例,那调用的就是拷贝构造函数;如果没有,那就是对已有的对象赋值,调用的是赋值运算符。

调用拷贝构造函数主要有以下场景:

  1:对象作为函数的参数,以值传递的方式传给函数。

  2:对象作为函数的返回值,以值的方式从函数返回。

  3:使用一个对象给另一个对象初始化。

代码如下:

 1 #include <iostream>
 2
 3 using namespace  std;
 4 class Person
 5 {
 6 public:
 7     Person() {}
 8     Person( const Person& p )
 9     {
10         cout << "Copy Constructor" << endl;
11     }
12
13     Person& operator=( const Person& p )
14     {
15         cout << "Assign" << endl;
16         return *this;
17     }
18
19 private:
20     int age;
21     string name;
22 };
23
24 void f( Person p )
25 {
26     return;
27 }
28
29 Person f1( )
30 {
31     Person p;
32     return p;
33 }
34
35
36 int main()
37 {
38     Person p;
39     Person p1 = p;    //  1
40     Person p2;  //
41     p2 = p;           // 2
42     f(p2);            // 3
43
44     p2 = f1();        // 4
45
46     Person p3 = f1(); // 5
47
48     return 0;
49 }

1:虽然使用了“=”,但是实际上使用对象p来创建了一个新的对象p1.也就是产生了新的对象,所以调用的是拷贝构造函数。

2:首先声明了一个对象p2,然后使用复制运算符"=",将p的值赋值给p2,显然是调用了赋值运算符,为一个已经存在的对象赋值。

3:以值传递的方式将对象p2传入函数f内,调用拷贝构造函数构建一个函数f可用的实参

4:这条语句拷贝构造函数和赋值运算符都调用了。函数f1以值的方式返回一个Person对象,在返回时会调用拷贝构造函数创建一个临时对象tmp作为返回值;返回后调用赋值运算符将临时对象tmp赋值给p2.

5:应该是首先调用拷贝构造函数创建临时对象;然后再调用拷贝构造函数使用刚才创建的临时对象创建新的对象p3,也就是会调用两次拷贝构造函数。不过,编译器也没有那么傻,应该是直接调用拷贝构造函数使用返回值创建了对象p3。

原文地址:https://www.cnblogs.com/cxq0017/p/10620273.html

时间: 2024-10-11 16:37:07

C++ 拷贝构造函数和赋值运算符的相关文章

第五篇:明确拒绝不想编译器自动生成的拷贝构造函数和赋值运算符重载函数

前言 如果你不想要编译器帮你自动生成的拷贝机制 (参考前文),那么你应当明确的拒绝. 如何拒绝?这便是本文要解决的主要问题. 问题描述 当你定义了一个类,而这个类中各对象之间也是封装的 - 禁止同类对象之间的相互赋值以及复制,那么你需要屏蔽掉编译器帮你生成的拷贝构造函数以及赋值运算符. 在许多代码中,会看到通过将拷贝构造函数和赋值运算符重载函数声明为私有且不予实现来实现这个功能.然而,这不是最科学的做法. 因为这没有做到真正的屏蔽:你在自己的成员函数中,或者友元函数中仍然可以调用这两个私有函数,

[QT入门篇]3 QObject的拷贝构造函数与赋值运算符

本文主要是针对QObject的拷贝构造函数和赋值运算符进行说明.先来看一下拷贝构造函数定义:拷贝构造函数,又称复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化.其唯一的形参必须是引用,但并不限制为const,一般普遍的会加上const限制.此函数经常用在函数调用时用户定义类型的值传递及返回.拷贝构造函数要调用基类的拷贝构造函数和成员函数.如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用. 还记得<[QT入门篇]1 QT中的对象模型>中

明确拒绝不想编译器自动生成的拷贝构造函数和赋值运算符重载函数

前言 如果你不想要编译器帮你自动生成的拷贝机制 (参考前文),那么你应当明确的拒绝. 如何拒绝?这便是本文要解决的主要问题. 问题描述 当你定义了一个类,而这个类中各对象之间也是封装的 - 禁止同类对象之间的相互赋值以及复制,那么你需要屏蔽掉编译器帮你生成的拷贝构造函数以及赋值运算符. 在许多代码中,会看到通过将拷贝构造函数和赋值运算符重载函数声明为私有且不予实现来实现这个功能.然而,这不是最科学的做法. 因为这没有做到真正的屏蔽:你在自己的成员函数中,或者友元函数中仍然可以调用这两个私有函数,

不使用编译器自动生成的拷贝构造函数和赋值运算符的方法

方法1:声明私有的拷贝构造函数和赋值运算符,这样不但阻止了编译器生成默认版本,并且使得用户无法调用他们,但是这时成员函数和友元函数还是可以调用他们,为了阻止他们的调用可以不定义这些私有的拷贝构造函数和赋值运算符.(标准库中也是如此阻止拷贝的) 代码段1.1:HomeForSale.h文件 #ifndef HOMEFORSALE_H #define HOMEFORSALE_H class CHomeForSale { public: CHomeForSale(){} private: CHomeF

关注C++细节——含有本类对象指针的类的构造函数、析构函数、拷贝构造函数、赋值运算符的例子

本例只是对含有本类对象指针的类的构造函数.析构函数.拷贝构造函数.复制运算符使用方法的一个简单示例,以加深对构造函数和拷贝控制成员的理解. 读C++ primer 5th 第13章后加上自己的理解,完整的写了下课后习题的代码. 第一版: #include <string> #include <iostream> using namespace std; class TreeNode{ private: string value; TreeNode *left; TreeNode *

拷贝构造函数和赋值运算符重载的区别

拷贝构造函数是用一个已存在的对象去构造一个不存在的对象(拷贝构造函数毕竟还是构造函数嘛),也就是初始化一个对象.而赋值运算符重载函数是用一个存在的对象去给另一个已存在并初始化过(即已经过构造函数的初始化了)的对象进行赋值. 它们定义上的区别,楼上的已经说过了. 比如:String s1("hello"),s2=s1;//拷贝构造函数Sring s1("hello"),s2;s1=s2;//赋值运算符重载以下情况都会调用拷贝构造函数:1.一个对象以值传递的方式传入函数

拷贝构造函数和赋值运算符的调用情况

很多情况下,对于 如下的说明,很难接受 int a(10); 其实完全等价于int a=10; 所以下面的情况更加难以接受: class A;//定义class A 应用: A a; A b(a);//其实完全等价于A b=a,调用的都是拷贝构造函数,在所有人的眼中如果不是,非常熟悉这样赋值的方式,还真是看做是赋值运算. 例子如下: void Test(A a) { } 在这个函数中,通过值的传递,其实调用的是拷贝构造函数,而没有调用赋值运算符,或者默认的构造函数, class T { publ

c++拷贝构造函数、赋值运算符=重载、深拷贝与浅拷贝

 关键词:构造函数,浅拷贝,深拷贝,堆栈(stack),堆heap,赋值运算符 摘要: 在面向对象程序设计中,对象间的相互拷贝和赋值是经常进行的操作. 如果对象在申明的同时马上进行的初始化操作,则称之为拷贝运算.例如: class1 A("af"); class1 B=A; 此时其实际调用的是B(A)这样的浅拷贝操作. 如果对象在申明之后,在进行的赋值运算,我们称之为赋值运算.例如: class1 A("af"); class1 B; B=A; 此时实际调用的类

拷贝构造函数与赋值运算符重载函数要点

拷贝构造函数 一个小例子 最近在<剑指Offer>上看到了一道题(程序如下),要求我们分析编译运行的结果,并提供3个选项: A. 编译错误: B. 编译成功,运行时程序崩溃:C. 编译运行正常,输出10. 1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 private: 7 int value; 8 9 public: 10 A(int n) { value = n; } 11 A(A other) {