繁体   English   中英

4级继承链中的C ++虚拟析构函数。

[英]C++ Virtual Destructors in a 4 level inheritance chain.

我正在对虚拟析构函数进行一些小实验以进行审查-想知道是否有人对以下内容有简单的解释(使用vs 2010):

我定义类层次结构ABCD,D继承C,C继承B,B继承A,A是Base;

进行了2个实验:

第一次实验-

A具有虚拟析构函数。

B具有非虚拟析构函数

C有一个虚拟的析构函数

D具有非虚拟析构函数

// ----------------------------

在类型D的堆上分配4个对象-将A *,B *和C *的指针指向前3个-将第4个对象作为D *保留完整性。 删除所有4个指针。

如我所料,在所有4种情况下,完整的析构函数链都以从D到A的相反顺序执行,从而释放了所有内存。

第二次实验-

A具有非虚拟析构函数**将A更改为非虚拟

B具有非虚拟析构函数

C有一个虚拟的析构函数

D具有非虚拟Distructor

在类型D的堆上分配4个对象-将A *,B *和C *的指针指向前3个-将第4个对象作为D *保留完整性。

删除C *和D *指针:完整的析构函数链以从D到A的相反顺序执行,从而释放了所有内存。

删除B *:B,然后运行A析构函数(泄漏)

删除A *:仅运行析构函数(泄漏)

谁能解释为什么?

在实验2中分配D类对象时,其直接基类(C)具有虚拟析构函数-难道这不告诉编译器使用Vptr对其进行跟踪并知道内存类型吗? 不管参考?

谢谢迈克

在实验2中分配D类对象时,其直接基类(C)具有虚拟析构函数-难道这不告诉编译器使用Vptr对其进行跟踪并知道内存类型吗? 不管参考?

没有。

在第二个测试用例中, AB没有vptrs / vtables。 (即使这样做,非虚拟成员函数仍将静态解决,而不是动态解决。)

换句话说,基类不“继承”派生类的信息(例如,函数是否是虚拟的)。

当您删除不带虚拟析构函数的A *时,编译时编译器不知道它将在运行时指向带有虚拟析构函数的对象。 删除可能是带有虚拟析构函数的对象-或没有。 动态绑定不会发生。

您是否真正在问为什么要使用虚拟和非虚拟析构函数? 具有非虚拟析构函数的基类的Cos不好。 查看常见问题

我提出了几乎相同的问题,因此我想分享一下。

请注意,为了说明它是如何工作的,我还在不同Ctor的内部添加了一些虚函数用法(不久,在每个Ctor中,V表仅“更新”至此),这意味着将要实现的虚函数实现直到继承链的“这一点”为止,被调用的是最派生的。

我的注释:在运行给定类的示例代码中,我还在堆栈上添加了一个“派生”对象(B和D)的创建->以强调与“虚拟性”有关的所有注意事项当我们使用指向类实例的指针(任何类型)时,Dtor的值是适用的。

class A;

void callBack(A const& a);

class A 
{

    public:
    A() { std::cout << "A Ctor " << std::endl; f1(); callBack(*this); /* f3();*/ }
    ~A() { std::cout << "A Dtor " << std::endl; }

    void f1() { std::cout << "A : f1 " << std::endl; }
    virtual void f2() const { std::cout << "A : f2 " << std::endl; }
    virtual void f3() = 0;
};


class B : public A 
{
    public: 
    B() { std::cout << "B Ctor " << std::endl;  f1(); callBack(*this); f3(); }
    ~B() { std::cout << "B Dtor " << std::endl; }
    void f1 () { std::cout << "B : f1 " << std::endl;}
    void f2() const { std::cout << "B : f2 " << std::endl; }
    virtual void f3() { std::cout << "B : f3 " << std::endl; }

};


class C : public A 
{
    public:
    C() { std::cout << "C Ctor " << std::endl; f1(); callBack(*this); f3(); }
    virtual ~C() { std::cout << "C Dtor " << std::endl; }
    void f1() { std::cout << "C : f1" << std::endl;}
    void f2() const { std::cout << "C : f2" << std::endl; }
    virtual void f3() const { std::cout << "C : f3" << std::endl; }

};

class D : public C 
{
    public:
    D() { std::cout << "D Ctor " << std::endl;  f1(); callBack(*this); }
    ~D() { std::cout << "D Dtor " << std::endl; }
    void f1() { std::cout << "D : f1" << std::endl; }
    void f2() const { std::cout << "D : f2 " << std::endl; }
    virtual void f3() { std::cout << "D : f3 " << std::endl; }

};

void callBack(A const& a) { a.f2(); }

// =================================================================================================================================

int main()
{
    std::cout << "Start of main program" << std::endl;

    std::cout << "Creating a D object on the heap" << std::endl;
    D* pd = new D;
    C* pc = new D;
    A* pa = new D;

    if (true)
    {
        std::cout << "Entering Dummy scope # 1 and creating B object on the stack" << std::endl;
        B b;
        std::cout << "Leaving Dummy scope # 1 with B object within it" << std::endl;
    }

    if (true)
    {
        std::cout << "Entering Dummy scope # 2 and creating D object on the stack" << std::endl;
        D d;
        std::cout << "Leaving Dummy scope # 2 with D object within it" << std::endl;
    }

    std::cout << "Calling delete on pd (D*) which points on a D object" << std::endl;
    delete pd;

    std::cout << "Calling delete on pc (C*) which points on a D object" << std::endl;
    delete pc;

    std::cout << "Calling delete on pa (A*) which points on a D object" << std::endl;
    delete pa;

   std::cout << "End of main program" << std::endl;
   return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM