I'm building a little nest for a personal thing . They are classes that encapsulate pointers to structures of a library written in C. I am using the classic technique pimpl
.
Note : the C library uses inheritance through struct
the classic method of defining macros with member-variables and declaring them struct
using said macros, so an inheritance relationship from C++ is not possible. Hence the use of pointers void *
.
The root class of my hierarchy is:
class TrivialPImpl {
public:
~TrivialPImpl( ) {
if( m_pimpl ) {
unlock( m_pimpl );
}
}
TrivialPImpl( void *ptr = nullptr ) : m_pimpl( ptr ) { }
TrivialPImpl( const TrivialPImpl &other ) = default;
TrivialPImpl( TrivialPImpl &&other ) : m_pimpl( const_cast< void * >( other.m_pimpl ) ) {
if( m_pimpl ) {
m_pimpl = nullptr;
}
}
protected:
virtual void unlock( void *ptr ) = 0;
private:
void *m_pimpl;
};
I expect the following to happen:
TrivialPimpl::unlock( )
is a pure virtual function, it is not possible to instantiate child classes without providing code forunlock( )
.As long as you don't define a destructor in any child class, calling a destructor (of any child) will cause calling
TrivialPImpl::~TrivialPImpl( )
From
TrivialPImpl::~TrivialPImpl( )
will be calledunlock( )
, which will execute the correct code dependent on the actual type of the destroyed instance.
Because of those points, I understand that it's impossible to get a pointer to an instance of a child class of TrivialPImpl
without it having the function implemented unlock( )
, so it's equally impossible TrivialPImpl
for a version of unlock( )
without a body to be called from the destructor of .
However, the compiler shows me 1 warning:
pure virtual 'virtual void TrivialPImpl::unlock()' called from destructor
Is my reasoning correct? Will the correct implementation of always be called
unlock( )
?If yes, what is the meaning of that compiler warning?
If not, what am I doing wrong?
I don't know much about c++ but I think this goes through the hierarchy when destructors are called.
I'll explain with an example:
The output of the program will be:
Here we can see that the destructor of the inheriting class will always be called before the destructor of the parent class; so when B is destroyed, when you try to call the unlock() method on class A's destructor, it will only find the virtual definition of A, hence the compile error.
It is recommended never to call virtual functions in constructors and destructors
From which we can extract: