问题
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