C++ Virtual Destructors in a 4 level inheritance chain.

社会主义新天地 提交于 2019-12-23 20:24:47

问题


I was doing a little experiment with virtual destructors to review - wondering if anyone has a simple explanation for the following (using vs 2010):

I Define class hierarchy A-B-C-D, D inherits C, C inherits B, B inherits A, A is the Base;

ran 2 experiments:

First experiment -

A has a virtual Destructor.

B has a non-Virtual Destructor

C has a virtual Destructor

D has a non virtual Destructor

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

Allocate 4 objects on the heap of type D - Point a pointer of A*, B* and C* at the first 3 - Leave the 4th as a D* for Completeness. Delete all 4 Pointers.

As I expected, in all 4 instances, the complete destructor chain is executed in reverse order from D down to A, freeing all memory.

Second Experiment -

A has a non-virtual Destructor ** Changed A to non virtual

B has a non-Virtual Destructor

C has a virtual Destructor

D has a non virtual Distructor

Allocate 4 objects on the heap of type D - Point a pointer of A*, B*, and C* at the first 3 - Leave the 4th as a D* for Completeness.

Deleting C* and D* pointers: the complete destructor chain is executed in reverse order from D down to A, freeing all memory.

Deleting B*: B and then A Destructor is run (leak)

Deleting A*: Only A Destructor is run (leak)

Can anyone explain Why this is?

When D type opjects are allocated in experiment 2, its immediate base class (C) has a virtual destructor - doesnt that tell the compiler to track it with a Vptr and know the memory type? REGARDLESS of the reference?

Thanks Mike


回答1:


When D type opjects are allocated in experiment 2, its immediate base class (C) has a virtual destructor - doesnt that tell the compiler to track it with a Vptr and know the memory type? REGARDLESS of the reference?

No.

In your second test case, A and B don't have vptrs/vtables. (And even if they did, a non-virtual member function would still be resolved statically, not dynamically.)

Put another way, a base class does not "inherit" information (such as whether functions are virtual) from derived classes.




回答2:


When you delete an A* without a virtual destructor, at compile-time the compiler does not know that it will point at runtime to an object with a virtual destructor. The deletion might be of an object with a virtual destructor -- or not. Dynamic binding does not occur.




回答3:


Is your actual question about why one would use virtual vs non-virtual destructors? Cos having a base class with a non-virtual destructor is bad. See the faq




回答4:


I have composed almost identical question, so I thought to share it.

Note that I also added some usage of virtual function within the different Ctor's in order to illustrate how it is work (shortly, in each Ctor, the V-table is updated only "up to it" , meaning the virtual function implementation that will be invoked is the most derived until "this point" of the inheritance chain).

A note of mine: In the sample code that runs the given classes, I also added a creation of "Derived" object (B and D) on the STACK --> in order to emphasis that all the considerations regarding "virtual-ness" of Dtor's are applicable when we use pointers (of whatever type) to the class instance.

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;
}


来源:https://stackoverflow.com/questions/11055089/c-virtual-destructors-in-a-4-level-inheritance-chain

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!