拷贝函数就是编译器自动帮你拷贝对象,自己却不需要实现拷贝方法。

那么我一直都有一个疑问,那么编译器到底有没有在类中给我们创建拷贝构造函数呢? 拷贝构造函数真的存在吗?

首先假设我们有下面两个类,一个Base类,一个Base的子类Child.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Base {
public:
Base(){
this->a = 3;
this->b = 4;
}

void setA(int a) {
this->a = a;
}

void setB(int b) {
this->b = b;
}
private:
int a;
int b;
};

class Child :public Base {
public:
Child() {
this->c = 5;
this->d = 6;
}
Child(const Child &child) {
this->c = child.d;
this->d = child.c;
}
private:
int c;
int d;

};

我们在Child类中自己定义了一个拷贝构造函数,那么子类肯定存在,如下图:

0.png

我们跳进这个function看一下里面发生了什么:

1.png

我们可以发现,这个function的确是我们自己写的拷贝构造函数。但是奇怪的是,在我们自己创建的拷贝构造函数里面竟然又调用了一个函数,但是我们自己并没有这么写呀。我们跳进去看一下这个是什么函数:

2.png

原来我们自己创造的拷贝构造函数自动调用了父类的空构造函数呀。这不就是普通构造函数的特点吗:如果不指定父类构造函数,那么自动调用父类的空构造函数。

这里可以看出,子类自己定义拷贝构造函数并不会自动调用父类的构造函数,而是和别的构造函数一样,自动调用父类的空构造函数

那么到底编译器有没有创建这个拷贝构造函数呢?

我们可以直接使用父类的所谓”拷贝构造函数”试一下:

3.png

我们可以看到,我们调用了所谓的”拷贝构造函数”,但是底层汇编语言只是简单的拷贝,并没有为我们开辟一个所谓的”拷贝构造函数”

那么讲到对象拷贝了,除了拷贝构造函数,还有一种方式为重载”=”操作符。

其实”=”操作符编译器也帮我们实现了对象的浅拷贝,底层和拷贝构造函数实现是一样的。

但是如果重载,方式就不一样的,一个是构造函数重载,一个是普通函数重载。

如果我们使用拷贝构造函数,那么我们overwrite的就是构造函数,要使用构造函数的方式使用父类的构造函数 (“:ParentConstructor(arg1, arg2,…)”)。

如果我们使用”=” operator,那么我们就相当于overwrite普通的函数,这个时候要用普通函数的方法来使用父类方法(“ParentClass::operator=(arg1)”)。

Conclusion:

拷贝构造函数其实就是一个假函数,编译器并没有为我们创造一个函数来copy对象。编译器做的只是简单的复制数据。而且是 浅拷贝:只简单拷贝数据,不拷贝指针里面的东西。

如果需要 深拷贝,则需要自己去写一个拷贝函数。