问题
I wonder is it correct to define a base class with no virtual destructor, and define inherited classes with the virtual one? What would actually happen if I do that?
回答1:
If you delete p
where p
is of type X*
but actually points to a Y
which is derived from X
, you have undefined behavior unless X
has a virtual
destructor. If Y
's destructor is virtual
but X
s destructor is not it changes exactly nothing.
回答2:
If you intend to do
delete pB;
where pB
is of type Base*
and pB
might point to an object of type Derived
, where Derived
is a (direct or indirect) derived class of Base
, then,
you must declare a virtual destructor for Base
.
So long as you don't intend to do this, it is fine for Base
to not have a virtual destructor.
In particular, if you have class B1
with a non-virtual destructor, and a class B2
that derives from B1
with a virtual destructor, and a class D
that derives from B2
, it is fine to use a pointer to B2
to delete an object of type D
, since B2
has a virtual destructor... but it would be undefined behaviour to use a pointer to B1
to delete an object of type B2
or D
, since B1
does not have a virtual destructor.
In any case, the idea of a function being virtual
in a derived class and non-virtual
in a base class is confusing, so I would not do it unless I had a very good reason.
回答3:
A virtual destructor allows you to invoke the correct destructor with just a pointer to the baseclass. Without the virtual destructor, delete base_ptr
will only invoke the base-class' destructor (or invoke undefined behaviour). However, whether the destructor call is dispatched dynamically depends only on the base class, so if the baseclass doesn't make it virtual, this will not suddenly become a virtual dispatch if some derived class adds a virtual destructor!
Notes:
- If the baseclass doesn't have a virtual destructor, don't use it as a baseclass. At most, use private/protected inheritance, but not public inheritance.
- If you write the baseclass but don't want to require a virtual destructor (common when writing mixins), you can make the destructor protected instead.
These two advises prevent accidental calls to the non-virtual baseclass destructor.
回答4:
It won't work if you don't declared virtual in parent class.
[~/cpp/VirtualDestructor]$ cat main.cpp
class A
{
public:
~A() {}
};
class B : public A
{
public:
B() : val(new char) {}
virtual ~B() { delete val; }
private:
char* val;
};
int main()
{
A* x = new B;
delete x;
}
[~/cpp/VirtualDestructor]$ valgrind ./run
==20382== Memcheck, a memory error detector
==20382== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==20382== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==20382== Command: ./run
==20382==
==20382==
==20382== HEAP SUMMARY:
==20382== in use at exit: 1 bytes in 1 blocks
==20382== total heap usage: 2 allocs, 1 frees, 17 bytes allocated
==20382==
==20382== LEAK SUMMARY:
==20382== definitely lost: 1 bytes in 1 blocks
==20382== indirectly lost: 0 bytes in 0 blocks
==20382== possibly lost: 0 bytes in 0 blocks
==20382== still reachable: 0 bytes in 0 blocks
==20382== suppressed: 0 bytes in 0 blocks
==20382== Rerun with --leak-check=full to see details of leaked memory
==20382==
==20382== For counts of detected and suppressed errors, rerun with: -v
==20382== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
[~/cpp/VirtualDestructor]$
B
instance is pointed by a A*
pointer. Then when you delete
it. It will go through the destructor of A
if A
's destructor is not virtual
来源:https://stackoverflow.com/questions/27534500/what-if-the-virtual-destructor-defined-in-derived-class-but-not-the-top-of-hier