C++ 继承(二、子类的构造函数和析构函数)

要点详解:

一、子类隐式调用基类的构造函数

    说明:

        如果子类的构造函数没有显式地调用基类的构造函数,那么系统就会调用基类的无参构造函数,

       但是前提是基类必须有无参构造函数; 如果基类中没有无参构造函数编译将报错。(提示:没有匹配的函数)

     实例:  

/*子类的构造*/
#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的析构函数,导致内存泄漏;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值