前言

类的构造函数如果没有特别定义,则会使用默认的构造函数,即空的情况,调用了也没变化。


正文

构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>

class father{
public:
int x;
int y;
father(){
std::cout << "father created\n";
}
};

int main(){

father fh;

return 0;
}

当实例化一个类的时候,然后我们特定构造函数有输出。

这便是最常见的情况。

那么当类的派生类出现的时候,实例化这个派生类,会调用什么构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class father{
public:
int x;
int y;
father(){
std::cout << "father created\n";
}
};

class son :public father{
public:
int age;
son(){
std::cout << "son created\n";
}
};

显然实例化的派生类的时候,他在继承基类的属性时,会一并执行构造函数。
并且也是按照继承顺序执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class father{
public:
int x;
int y;
father(){
std::cout << "father created\n";
}
};

class son :public father{
public:
int age;
son(){
std::cout << "son created\n";
}
};

class grandson :public son{
public:
grandson(){
std::cout << "grandson created\n";
}
};

可以看到继承的顺序,决定了构造函数的执行顺序。


副本构造函数

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
class father{
public:
int x;
int y;
father(){
std::cout << "father created\n";
}
father(const father &f){
std::cout << "father copy created\n";
}
};

class son :public father{
public:
int age;
son(){
std::cout << "son created\n";
}
son(const son &s){
std::cout << "son copy created\n";
}
};

class grandson :public son{
public:
grandson(){
std::cout << "grandson created\n";
}
grandson(const grandson &g){
std::cout << "grandson copy created\n";
}
};

结果似乎有点超出预期,在执行=的时候,发现只进行了一次copy。
说明类在继承的时候只会调用基类的构造函数,而不会调用副本构造函数。

想要人为干预的时候,需要用到以前的列表初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
class son :public father{
public:
int age;
son(){
std::cout << "son created\n";
}
son(const son &s){
std::cout << "son copy created\n";
}
son(int _age) :age{ _age }{

}
};

既然已经新增了构造函数,那么副本构造就也可以使用列表方式初始化

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
35
class father{
public:
int x;
int y;
father(){
std::cout << "father created\n";
}
father(const father &f){
std::cout << "father copy created\n";
}
};

class son :public father{
public:
int age;
son(){
std::cout << "son created\n";
}
son(const son &s) :father{s}{
std::cout << "son copy created\n";
}
son(int _age) :age{ _age }{

}
};

class grandson :public son{
public:
grandson(){
std::cout << "grandson created\n";
}
grandson(const grandson &g) :son{g}{
std::cout << "grandson copy created\n";
}
};

一环套一环的操作之后。再看看它的拷贝顺序。

看到手动创建了新的构造函数之后,在副本构造函数上同样使用列表初始化的操作,他就可以无缝衔接上了。

当然这也是继承的特点之一。
因为类的副本构造函数它是有要求传入的数据类型,我们用grandson去进行拷贝,通过继承,它用基类套基类,只不过现在只能浅述。

因为这个特性,他甚至可以直接这样完成拷贝。


派生类中的副本构造函数并不会自动调用基类的副本构造函数,需要我们手动指定。


继承构造函数

通过using基类::基类构造函数可以继承基类构造函数,但是默认构造函数与副本构造函数不会被继承。

1
using son::son;

通过强制指定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class son :public father{
public:
int age;
son(){
std::cout << "son created\n";
}
son(const son &s) :father{s}{
std::cout << "son copy created\n";
}
son(int _age) :age{ _age }{
std::cout << _age << std::endl;
}
};

class grandson :public son{
public:
using son::son;
grandson(){
std::cout << "grandson created\n";
}
grandson(const grandson &g) :son{g}{
std::cout << "grandson copy created\n";
}
};

可以看到grandson强制继承了构造函数之后,我们实例化的时候进行初始化,他会直接调用我们的基类son去完成构造。

并且这个解锁因为是构造函数,所以在派生类的private中解锁,效果也是一样的。
因为继承的成员没有指定函数()里面的形参,所以继承的时候会带上重载的


结语

构造完还有析构。