要点详解:
一、子类隐式调用基类的构造函数
说明:
如果子类的构造函数没有显式地调用基类的构造函数,那么系统就会调用基类的无参构造函数,
但是前提是基类必须有无参构造函数; 如果基类中没有无参构造函数编译将报错。(提示:没有匹配的函数)
实例:
/*子类的构造*/
#include <iostream>
using namespace std;
class A{
public:
A(int n){
cout<<"A的有参构造"<<endl;
}
};
class B :public A{
public:
B(void){
cout<<"B的无参构造"<<endl;
}
};
int main(void)
{
B b1;
return 0;
}
解析:(程序编译不通过)
1、子类隐式调用基类的构造函数
2、系统不会为基类提供默认无参构造函数,因为已经存在有参构造函数
3、解决办法:手动添加基类的无参构造函数 或者用下面的办法
B(void){ cout<<"B的无参构造"<<endl; }
改成:
B(void):A(0){ cout<<"B的无参构造"<<endl; }
二、子类显式调用基类的构造函数
说明:
每个子类的实例化对象中都包含其基类的实例化子对象
即子类对象中的基类子对象,该子对象是由基类的构造函数创建并初始化的;
实例:
/*子类的构造*/
#include <iostream>
using namespace std;
class A{
public:
A(void){
cout<<"A的无参构造"<<endl;
}
A(int n){
cout<<"A的有参构造"<<endl;
}
};
class B :public A{
public:
B(void):A(0){
cout<<"B的无参构造"<<endl;
}
B(int n):A(n){
cout<<"B的有参构造"<<endl;
}
};
int main(void)
{
B b(10);
return 0;
}
结果:
A的有参构造
B的有参构造
解析:
1、B(int n):A(n) 初始化列表
2、程序先构造基类的部分 再才是子类的部分
三、构造和析构的顺序
构造:基类的构造函数---构造基类子对象---基类构造函数的代码----子类构造函数代码
析构:顺序是反的
四、子类和基类构造函数调用解析
1、子类没有自定义构造函数--系统会提供默认的无参构造函数
1.1 基类没有定义构造函数:
用子类定义对象时,先自动调用基类的默认无参构造函数,再调用子类的默认无参构造函数
1.2基类 自定义了无参构造函数:
用子类定义对象时,先自动调用基类的自定义无参构造函数,再调用子类的默认无参构造函数
1.3基类中定义了有参构造函数 没有定义无参构造函数
用子类定义对象时,编译器提示:没有匹配的函数调用
2、子类自定义构造函数但是没有调用基类的构造函数 (无参、有参)
2.1基类没有自定义构造函数
用子类定义对象时,先自动调用基类的默认无参构造函数,再调用子类的自定义造函数
2.2基类自定义无参构造函数
用子类定义对象时,先自动调用基类的自定义无参构造函数,再调用子类的自定义造函数
2.3基类中定义了构造函数(带参的)
用子类定义对象时,编译器提示:没有匹配的函数调用
上述用if表示:
if(子类没有自定义构造函数)
{
if(基类没有自定义构造函数)
{
用子类定义对象时,先自动调用基类的默认构造函数,再调子类的默认构造函数。
}
else if(基类有自定义无参构造函数)
{
用子类定义对象时,先自动调用基类的自定义无参构造函数,再调子类的默认构造函数。
}
else
{
用子类定义对象时,编译提示没有默认构造函数可用
}
}
else if(子类自定义构造函数但没有调用基类的某个构造函数)
{
if(基类没有自定义构造函数)
{
用子类定义对象时,先自动调用基类的默认构造函数,再调子类的自定义构造函数。
}
else if(基类有自定义无参构造函数)
{
用子类定义对象时,先自动调用基类的自定义无参构造函数,再调子类的自定义构造函数。
}
else
{
用子类定义对象时,编译提示没有默认构造函数可用
}
}
五、总结
1、子类的析构函数会自动地调用基类的析构函数,析构其基类子对象.但是基类析构函数不会调用子类的析构函数.
因此,通过基类指针析构子类对象,实际被调用的是基类的析构函数,实际被析构的仅仅是子类对象中的基类子对象,
而子类的扩展部分将构成内存泄漏;
2、基类分配资源,基类提供析构,子类未分配资源,子类无需提供析 构.(子类里缺省析构也可以调用基类的析构);
如果基类分配资源,基类提供析构,子类分配资源,子类必须提供析构;(谁分配资源,谁写析构);
实例:
#include <iostream>
using namespace std;
class A{
public:
A(void){
cout<<"A的无参构造"<<endl;
}
A(int n){
cout<<"A的有参构造"<<endl;
}
~A(){
cout<<"A的析构函数"<<endl;
}
};
class B :public A{
public:
B(void):A(0){
cout<<"B的无参构造"<<endl;
}
B(int n):A(n){
cout<<"B的有参构造"<<endl;
}
~B(void){
cout<<"B的析够函数"<<endl;
}
};
int main(void)
{
A*pa = new B(10);
delete pa;
return 0;
}
结果:
A的有参构造
B的有参构造
A的析够函数
解析:
1、delete pa; 基类A的指针指向B,在释放指针时,只调用了A的析构函数,从而无法调用B的析构函数,导致内存泄漏;