[ fromfile: vtable.xml id: vtable ]
Each class that contains methods (virtual
functions) has a virtual jump table, or vtable,
The compiler substitutes function names with indirect (relative to the vtable list) references to method calls.
Each instance of a polymorphic type has a typeid
, which can be quite naturally implemented as the address of the vtable for the class.
A vtable cannot be built for a class unless the method definitions for all overrides are fully defined and findable by the linker.
The typeid
of an object is set after the object's constructor has executed.
If there are base classes, the typeid
for an object may be set multiple times, after each base class initialization.
Example 22.1. src/derivation/typeid/vtable.h
[ . . . . ] class Base { protected: int m_X, m_Y; public: Base(); virtual ~Base(); virtual void virtualFun() const; }; class Derived : public Base { int m_Z; public: Derived(); ~Derived(); void virtualFun() const ; }; [ . . . . ]
Example 22.2 shows what happens when a virtual
function is called from a base class constructor or destructor.
Example 22.2. src/derivation/typeid/vtable.cpp
#include <QDebug> #include <QString> #include "vtable.h" Base::Base() { m_X = 4; m_Y = 12; qDebug() << " Base::Base: " ; virtualFun(); } Derived::Derived() { m_X = 5; m_Y = 13; m_Z = 22; } void Base::virtualFun() const { QString val=QString("[%1,%2]").arg(m_X).arg(m_Y); qDebug() << " VF: the opposite of Acid: " << val; } void Derived::virtualFun() const { QString val=QString("[%1,%2,%3]") .arg(m_X).arg(m_Y).arg(m_Z); qDebug() << " VF: add some treble: " ; } Base::~Base() { qDebug() << " ~Base() " ; virtualFun(); } Derived::~Derived() { qDebug() << " ~Derived() " ; } int main() { Base *b = new Derived; b->virtualFun(); delete b; }
In the output that follows, you can see that the derived virtualFun()
does not get called from Base::Base() because the base class initializer is inside an object that is not yet a Derived
instance.
Base::Base: VF: the opposite of Acid: "[4,12]" VF: add some treble: ~Derived() ~Base() VF: the opposite of Acid: "[5,13]"
Calling virtual
methods from destructors is also not recommended.
In the previous output, you can see that the base virtualFun
is always called from the base class constructors or destructor.
Dynamic binding does not happen inside constructors or destructors.
"From a constructor or destructor, virtual methods aren't. [Meyers]"
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |