Virtual Pointers and Virtual Tables

Each class that contains methods (virtual functions) has a virtual jump table, or vtable, which is generated as part of the "lightweight" C++ execution environment. The vtable can be implemented in a number of ways, but the simplest implementation (which is often the fastest and most lightweight) contains a list of pointers to all methods of that class. Depending on the optimization policies, it may contain additional information to aid in debugging. The compiler substitutes function names with indirect (relative to the vtable list) references to method calls.

With this in mind, we can define polymorphic type explicitly as a class that contains one or more methods and, thus, requires the use of a vtable. Each instance of a polymorphic type has a typeid, which can be quite naturally implemented as the address of the vtable for the class.

vtable instead of switch

To implement indirect method calling through vtables, the compiler generates a jump table, which is similar to a switch statement, for each polymorphic class. Programmers can often exploit vtables instead of writing their own switch statements or large compound conditionals. This is implicit in a number of design patterns such as the Command, Visitor, Interpreter, and Strategy patterns.


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 objects constructor has executed. If there are base classes, the typeid for an object may be set multiple times, after each base class initialization. We will use the classes defined in Example 23.1 to demonstrate that calling a virtual function from a constructor or destructor can have unexpected consequences.

Example 23.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 23.2 shows what happens when a virtual function is called from a base class constructor or destructor.

Example 23.2. src/derivation/typeid/vtable.cpp

#include 
#include 
using namespace qstd;
#include "vtable.h"

Base::Base() {
 m_X = 4;
 m_Y = 12;
 cout << " 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);
 cout << " VF: the opposite of Acid: " << val << endl;
}

void Derived::virtualFun() const {
 QString val=QString("[%1,%2,%3)")

 .arg(m_X).arg(m_Y).arg(m_Z);
 cout << " VF: add some treble: " << val << endl;
}

Base::~Base() {
 cout << " ~Base() " << endl;
 virtualFun();
}

Derived::~Derived() {
 cout << " ~Derived() " << endl;
}

int main() {
 Base b;
 Derived d;
}

In the output that follows, we see that the derived VF: 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]
Base::Base: VF: the opposite of Acid: [4,12]
~Derived()
~Base()
VF: the opposite of Acid: [5,13]
~Base()
VF: the opposite of Acid: [4,12]


Calling virtual methods from destructors is also not recommended. In the preceding output, we 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.



Part I: Introduction to C++ and Qt 4

C++ Introduction

Classes

Introduction to Qt

Lists

Functions

Inheritance and Polymorphism

Part II: Higher-Level Programming

Libraries

Introduction to Design Patterns

QObject

Generics and Containers

Qt GUI Widgets

Concurrency

Validation and Regular Expressions

Parsing XML

Meta Objects, Properties, and Reflective Programming

More Design Patterns

Models and Views

Qt SQL Classes

Part III: C++ Language Reference

Types and Expressions

Scope and Storage Class

Statements and Control Structures

Memory Access

Chapter Summary

Inheritance in Detail

Miscellaneous Topics

Part IV: Programming Assignments

MP3 Jukebox Assignments

Part V: Appendices

MP3 Jukebox Assignments

Bibliography

MP3 Jukebox Assignments



An Introduction to Design Patterns in C++ with Qt 4
An Introduction to Design Patterns in C++ with Qt 4
ISBN: 0131879057
EAN: 2147483647
Year: 2004
Pages: 268

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net