美文网首页
多继承中的虚函数与析构

多继承中的虚函数与析构

作者: 404Not_Found | 来源:发表于2021-09-04 15:06 被阅读0次
  • 作者: 雪山肥鱼
  • 时间:20210905 12:45
  • 目的: 多继承中的虚函数于析构

父类无虚析构的问题

直接抛异常

class Base
{
public:
    virtual void f()
    {
        cout << "Base::f()" << endl;
    }
    virtual void g()
    {
        cout << "Base::g()" << endl;
    }
    virtual void h()
    {
        cout << "Base::h()" << endl;
    }
};

class Base2
{
public:
    virtual void hBase2()
    {
        cout << "Base2::hBase2()" << endl();
    }
};

class Derive :public Base, public Base2
{
public:
    virtual void i()
    {
        cout << "Derive::self i()" << endl;
    }
    virtual void g()
    {
        cout << "Derive::g()" << endl;
    }
    void myselffunc() {}
};

int main(int argc, char**argv)
{
    Base2 *pb2 = new Derive();
    //根据布局得到 编译器可能是这么玩的:
    //Derive *temp = new Derive();
    //Base2 *pb2 = (Base2*)((char*)temp + sizeof(Base))

    delete pb2;//报异常了!
     

    return 0;
}

多继承中的析构

图片.png

注:只有多继承时,才会牵扯到this指针的调整

对于这行代码

Base2 *pb2 = new Derive();
//Base2 *pb2 = (Base2*)((char*)temp + sizeof(Base))
  • 如果base2里没有析构函数,编译器会直接删除以Base2为首的内存。则注定抛异常。
  • 同样对于base2 ,非虚函数的 析构函数来讲,一样的会抛异常。
  • 非虚函数的析构,编译器会把他当作普通成员函数,直接执行静态绑定

Base2 中有析构函数, 则调用顺序为
~Derive() -> ~Base2() -> ~Base();
Derive 此时如果没有虚析构函数,则编译器会自动为Derive 合成一个虚析构函数。进行调用。
主要是父类要有虚析构函数
索性统一编程规范:
编程规范:继承关系中一定要有虚析构,不能省略。子类的析构函数,加不加都行,最好都加上virtual标识

父类的析构函数是虚函数,则牵扯到虚函数表。析构时编译器会调整this指针,指向开头的Base,后续详谈。

多重继承的内存布局

图片.png
为Base Base2父类增加虚析构函数

多继承中的 thunk

同时发现 子类的 第二张虚函数表,即会多一个 thunk. 这东西专门用在多继承中。
从第二个虚函数表起,有这个东东。主要作用是:调整this指针 因为第一个父类和 子类共用同一张虚函数表,所以不用调整this指针。
thunk作用:

  1. 调整this 指针到对象开头
  2. 调用整个子类对象的析构函数(一组析构函数)
  • 流程:


    反汇编示意.png
图片.png

继承关系中 父类的析构函数必须为虚析构

  • 如果不是 只会析构 父类自己的部分,不会析构子类
  • 如果是,则虚析构函数在虚函数表中
    • 则子类的析构函数,用一组析构函数替换了父类虚函数表中的析构函数。如下(有顺序关系)
    1. 子类析构函数
    2. 父类析构函数
    • 如果是多继承关系
    1. 子类析构函数
    2. 父类2 析构函数
    3. 父类1 析构函数

相关文章

网友评论

      本文标题:多继承中的虚函数与析构

      本文链接:https://www.haomeiwen.com/subject/hmsjwltx.html