首页 > 拷贝构造函数和赋值函数的一些知识

拷贝构造函数和赋值函数的一些知识

/*******************拷贝构造函数和赋值运算符重载有以下两个不同之处***************************/

 

1.拷贝构造函数生成新的类对象,而赋值运算符不能。

2.由于拷贝构造函数是直接构造一个新的类对象,所以在初始化这个对象之前不用检验源对象是否和新对象相同,而复制操作符需要这个操作,另外赋值运算符中如果原来对象中有内存分配,要先把内存释放掉。

下面是String类的一个实现的部分函数,可以看出二者的区别。

 1 class String{
 2 public:
 3     String(const char * str = NULL);
 4     String(const String& other);
 5     ~String();
 6     String& operator=(const String& other);
 7 private:
 8     char *m_data;
 9 };
10 
11 String::String(const char * str){
12     if (str != NULL){
13         int length = strlen(str);
14         m_data = new char[length + 1];
15         strcpy(m_data, str);
16     }
17 }
18 
19 String::~String(){
20     delete m_data;
21 }
22 
23 String::String(const String& other){
24     int length = strlen(other.m_data);
25     m_data = new char[length + 1];
26     assert(m_data != NULL);
27     strcpy(m_data, other.m_data);
28 }
29 
30 String& String::operator=(const String& other){
31     if (this == &other){                 //这里要判断是否自我赋值
32         return *this;
33     }
34     if (m_data != NULL){                 //要检验是否有内存分配
35         delete m_data;
36     }
37     int length = strlen(other.m_data);
38     m_data = new char[length + 1];
39     assert(m_data == NULL);
40     strcpy(m_data, other.m_data);
41     return *this;
42 }

 

/**************一种调用拷贝构造函数和赋值函数的微妙差别*******************/

 

#include
#include
using namespace std;class B{
public:B():data(0){cout << "default constructor" << endl;}B(int i):data(i){cout << "constructed by parameter " << data << endl;}B (B &b){data = b.data;cout << "copyed by parameter " << data << endl;}B & operator=(const B& b){this->data = b.data;cout << "=     by parameter " << data << endl;return *this;}
private:int data;
};



void test(){

    B b1;

    B b2 = b1;

    B b3;

    b3 = b1;

}
int main(){



  test();
system("pause");return 0; }

test()函数和system("pause")是为了不退出main函数,可以看到析构函数执行。运行之后得到以下结果。

default constructor

copyed by parameter 0

default constructor

=     by parameter 0



注意仔细看test函数里的代码段。

b2调用的是拷贝构造函数,而b3调用的是赋值函数。这两者是不同的。

 

/*********************关于拷贝构造函数和赋值函数的临时对象问题******************************/

 

看以下代码,它的输出会是什么。

 1 #include
 2 #include
 3 using namespace std;
 4 
 5 class B{
 6 public:
 7     B():data(0){
 8         cout << "default constructor" << endl;
 9     }
10     ~B(){
11         cout << "destructed by parameter " << data << endl;
12     }
13     B(int i):data(i){
14         cout << "constructed by parameter " << data << endl;
15     }
16     B (B &b){
17         data = b.data;
18         cout << "copyed by parameter " << data << endl;
19     }
20     B & operator=(const B& b){
21         this->data = b.data;
22         cout << "=     by parameter " << data << endl;
23         return *this;
24     }
25 private:
26     int data;
27 };
28 
29 B play(B b){
30     return b;
31 }
32 
33 void test(){
34     play(1);
35     B t1 = play(2);
36     B t2;
37     t2 = play(3);
38 }
39 
40 int main(){
41 
42     test();
43     system("pause");
44     return 0;
45 }



这个程序比上一个增加了一个play()函数和析构函数的输出。看到输出结果后,有一些疑惑。以下为输出结果,为方便起见,给它们编号。

(1)constructed by parameter 1                                            

(2)copyed by parameter 1

(3)destructed by parameter 1

(4)destructed by parameter 1

(5)constructed by parameter 2

(6)copyed by parameter 2

(7)destructed by parameter 2

(8)default constructor

(9)constructed by parameter 3

(10)copyed by parameter 3

(11)destructed by parameter 3

(12)=     by parameter 3

(13)destructed by parameter 3

(14)destructed by parameter 3

(15)destructed by parameter 2



如果有疑问,可以先了解下面三点。

 

1.用同一个类的源对象构造一个目标对象是,会调用拷贝构造函数来构造目标对象,如果没有定义拷贝构造函数,将会调用默认的拷贝函数来构造目标对象。

2.当类有一个带有一个参数的构造函数时,可以用这个参数同类型的数据初始化这个对象,默认会调用这个构造函数。

3.当一个函数的返回值为一个类的对象时,如果在调用函数中(注意是调用函数,不是被调用函数),没有定义一个对象来接收这个返回值,会用返回一个临时对象保存返回对象的值。在被调用函数(注意是被调用函数)结束时,这个临时对象被销毁。而当有一个接收对象时,就将返回对象赋值给接收对象,这个返回对象在调用函数(注意是调用函数)结束时调用析构函数。

 

第一点体现在程序35行,上面讲过,这是会调用拷贝构造函数而不是赋值函数。

第二点体现在34行,play(1)的类型是整型,而类B中有一个带int类型的构造函数,当实参1传给形参b,会调用这个构造函数。

第三点体现在34行和37行。play(1)函数被调用,返回一个类对象,而此时没有对象接收(在左边接受赋值),所以会返回一个临时对象,而这个临时对象在被调用函数play结束时调用析构函数销毁,输出(4)destructed by parameter 1;t2 = play(3);语句中play(3)被调用,返回一个对象,而此时有对象(t2)接收,所以调用赋值函数赋值给t2,在调用函数(test)结束时,这个对象才被销毁输出(13)destructed by parameter 3。

 

所以,上面的输出的含义分别是:

constructed by parameter 1                  //用1构造参数b

copyed by parameter 1                        //用b构造一个临时对象

destructed by parameter 1                   //参数b被析构

destructed by parameter 1                   //临时对象被析构

constructed by parameter 2                 //用2构造参数b

copyed by parameter 2                        //用b构造t1

destructed by parameter 2                   //参数b被析构

default constructor                             //构造t2

constructed by parameter 3                 //用3构造参数b

copyed by parameter 3                       //用b拷贝一个临时对象

destructed by parameter 3                  //参数b被析构

=     by parameter 3                           //调用赋值函数=()初始化t2

destructed by parameter 3                 //临时对象被析构

destructed by parameter 3                 //t2被析构

destructed by parameter 2                 //t1被析构



转载于:https://www.cnblogs.com/piginthetree/p/3898487.html

更多相关:

  • 草色新雨中, 松声晚窗里。之前我们学习 Power Query 都是用鼠标就完成了很多复杂的操作。虽然 PowerQuery 已经将大部分常用功能内置成到功能区。基本能完成我们大部分的报表自动化功能。但是总有些复杂的或者个性化的问题是开发团队没有预先想到的,这时我们就需要学习 M 语言。一、M 语言在哪里?M语言的函数公式有三个地...

  • 前言从2020年3月份开始,计划写一系列文档--《小白从零开始学编程》,记录自己从0开始学习的一些东西。第一个系列:python,计划从安装、环境搭建、基本语法、到利用Django和Flask两个当前最热的web框架完成一个小的项目第二个系列:可能会选择Go语言,也可能会选择Vue.js。具体情况待定,拭目以待吧。。。基本概念表达式表...

  • 1.1函数1.1.1什么是函数函数就是程序实现模块化的基本单元,一般实现某一功能的集合。函数名:就相当于是程序代码集合的名称参数:就是函数运算时需要参与运算的值被称作为参数函数体:程序的某个功能,进行一系列的逻辑运算return 返回值:函数的返回值能表示函数的运行结果或运行状态。1.1.2函数的作用函数是组织好的,可重复使用的,用来...

  • 原标题:基于Python建立深度神经网络!你学会了嘛?图1 神经网络构造的例子(符号说明:上标[l]表示与第l层;上标(i)表示第i个例子;下标i表示矢量第i项)单层神经网络图2 单层神经网络示例神经元模型是先计算一个线性函数(z=Wx+b),接着再计算一个激活函数。一般来说,神经元模型的输出值是a=g(Wx+b),其中g是激活函数(...

  • 在学习MySQL的时候你会发现,它有非常多的函数,在学习的时候没有侧重。小编刚开始学习的时候也会有这个感觉。不过,经过一段时间的学习之后,小编发现尽管函数有很多,但是常用的却只有那几个。今天小编就把常用的函数汇总一下,为大家能够能好的学习MySQL中的函数。MySQL常使用的函数大概有四类。时间函数、数学函数、字符函数、控制函数。让我...

  • 这个课程的参考视频在youtube。     主要学到的知识点有: Create new project, choose Java Application.one .jar file/ package(.jar name with the same as package), one package can contains mutip...