c++ | 多态 | 虚基类析构函数 作用及分析

92 篇文章 0 订阅
文章详细解释了C++中当基类指针指向派生类对象时,构造函数和析构函数的执行过程,特别是当基类析构函数为虚函数时,如何确保正确调用派生类的析构函数。文章还提到虚函数表的作用和C++标准对析构函数执行顺序的规定。
摘要由CSDN通过智能技术生成

事情是这样的,虽然都知道,当基类对象指针指向开辟的派生类对象空间是,
基类、派生类的构造函数和析构函数是怎么走的。但是这其中的原理还是想一探究竟。
因为如果基类的析构函数不是虚函数,那么在释放空间的的时候,仅仅释放基类对象的空间,而开辟的派生类对象空间没有得到释放。

这里会牵扯到 虚函数表
怎么说虚函数表呢,每一个派生类对象都会有一张与之对应的继承关系的基类表,如果基类的虚函数在派生类中有实现,那么实际上的表中相关函数是培派生类的实现,而不是单一的基类实现,当然一般都建议在基类把“这个口子”写成纯虚函数,派生类去实现。

虚函数表的解析可以看大神,陈皓写的 陈皓—虚函数表解析

//然后写了一个c++ 的实现
// 打印三个函数
// 好像这种类型强转  还是有点生疏啊
#include <iostream>
#include <cstdint>  // for intptr_t

typedef void(*Func)(void);
class base{
    public:
        virtual void f(){ std::cout<<"base::f()"<<std::endl;}
        virtual void g(){ std::cout<<"base::g()"<<std::endl;}
        virtual void h(){ std::cout<<"base::h()"<<std::endl;}
};

int main()
{
    std::cout<<"Hello World"<<std::endl;

    base b;
    std::cout<<"基类对象b 的地址为:"<< &b <<std::endl;

    intptr_t** vtable = (intptr_t**)(&b);
    for (int i = 0; i < 3; ++i) {
        Func pfun = (Func)(*vtable)[i];
        std::cout<<"虚函数表第"<< i+1 <<"个虚函数地址:"<< pfun <<std::endl;
        std::cout<<"start...."<<std::endl;
        pfun();
        std::cout<<"end...."<<std::endl;
    }

    return 0;
}

但是我心中的疑惑还是没有解开,
于是问问ai
是的,这个行为是由 C++ 的标准定义的。在 C++ 中,如果基类的析构函数是虚函数,那么在删除一个通过基类指针指向的派生类对象时,会首先调用派生类的析构函数,然后调用基类的析构函数。这是由 C++ 的动态绑定机制保证的。

这个行为在 C++ 的标准中有明确的规定。在 C++11 标准的 12.4 节(Destructors)中,有以下的规定:

After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct non-variant non-static data members, the destructors for X’s direct base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for X’s virtual base classes. All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes. Bases and members are destroyed in the reverse order of the completion of their constructor (see 12.6.2). A return statement (6.6.3) in a destructor might not directly return to the caller; before transferring control to the caller, the destructors for the members and bases are called. Destructors for elements of an array are called in reverse order of their construction (see 12.6).

这段话的意思是,析构函数首先执行其主体,然后销毁在主体中分配的任何自动对象,然后调用类的直接非变量非静态数据成员的析构函数,然后调用类的直接基类的析构函数,如果类是最派生类的类型,那么它的析构函数会调用虚基类的析构函数。所有的析构函数都被当作是使用限定名引用的,也就是说,忽略在更派生的类中可能覆盖的虚析构函数。基类和成员是按照完成它们的构造函数的逆序被销毁的。在析构函数中的 return 语句可能不直接返回给调用者;在将控制权转移给调用者之前,会调用成员和基类的析构函数。数组的元素的析构函数是按照它们的构造函数的逆序被调用的。

最后得出的结论是,这是死定义,是c++给出的定义,就像 int 表示整型,char 表示字符型

  • 16
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值