前言
类的构造函数如果没有特别定义,则会使用默认的构造函数,即空的情况,调用了也没变化。
正文
构造函数
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 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中解锁,效果也是一样的。
因为继承的成员没有指定函数()里面的形参,所以继承的时候会带上重载的
结语
构造完还有析构。