Virtual Functions support dynamic binding and object-oriented programming. A class that declares or inherits a virtual function is called a polymorphic class.
2. ISO/IEC 14882:1998(E). International Standard.
First Edition 1998-09-01
10.3 Virtual Functions
10.3.1 Virtual Functions support dynamic binding and object-
oriented programming. A class that declares or inherits a virtual
function is called a polymorphic class.
If a virtual member function vf is declared in a class Base and in a
class Derived, derived directly or indirectly from Base, a member
function vf with the same name and same parameter list as Base::vf
is declared, then Derived::vf is also virtual (whether or not it is so
declared) and it overrides Base::vf. For convenience we say that
any virtual function overrides itself.
C++ standard does not say anything about implementation of
virtual functions. The compilers are free to implement it by
any (correct) mechanism. However, practically majority of the
compilers that exist today implement virtual functions using
vtable mechanism.
3. Example
class Transaction // base class for all transactions
{
public:
Transaction();
virtual void logTransaction() const = 0; // make type-dependent log entry
//...
};
Transaction::Transaction() // implementation of base class constructor
{
//...
logTransaction(); // as final action, log this transaction
}
class BuyTransaction : public Transaction // derived class
{
public:
virtual void logTransaction() const; // how to log transactions of this type
//...
};
class SellTransaction : public Transaction // derived class
{
public:
virtual void logTransaction() const; // how to log transactions of this type
//...
};
BuyTransaction b;
4. General classes
class A at the code generation
{ level:
int foo(); struct D
{
int a1; int a1;
int a2; int a2;
int a3;
int a3;
}; int b1;
class B int b2;
{ int b3;
int bar(); int d1;
int d2;
int b1; int d3;
int b2; };
int b3; ?foo@A@@ModuleA@(A* pThis);
}; ?bar@B@@ModuleB@(B* pThis);
class D : public A, public B ?foo@D@@ModuleD@(D* pThis);
{
int foo(); D::D() {}
int d1;
int d2; A::foo( (A*)&D );
int d3;
};
A* pA = new D;
pA->foo();
5. Virtual Functions
class Vbase at the code generation level:
struct Vbase
{ { static struct VbTable
virtual void foo(); void* m_pVptr; // {
virtual void bar(); int a1; void (*foo)();
};
int a1; ?foo@Vbase@@ModuleVb@(Vbase* pThis); void (*bar)();
?bar@Vbase@@ModuleVb@(Vbase* pThis); };
};
cBase.m_pVptr[foo_idx](&cBase);
Vbase cBase; struct V
{
cBase.foo(); void* m_pVptr; // static struct VTable
int a1; {
int b1; void (*foo)();
}; void (*bar)();
class V : public Vbase void (*dir)();
?foo@V@@ModuleV@(V* pThis); void (*alpha)();
{ ?dir@V@@ModuleV@(V* pThis);
?alpha@V@@ModuleV@(V* pThis); };
void foo();
virtual void dir();
virtual void alpha();
int b1;
};
6. Class Constructors
class Vbase at the code generation level:
{ Vbase::Vbase
virtual void foo(); {
virtual void bar(); m_pVptr->[0] = void(*foo)();
virtual void dir() = 0; m_pVptr->[1] = void(*bar)();
void do() m_pVptr->[2] = 0;
{ };
foo();
}
int a1; V::V : Vbase()
{
}; m_pVptr->[0] = void(*foo)();
m_pVptr->[1] = void(*Vbase::bar)();
m_pVptr->[2] = void(*dir)();
class V : public Vbase m_pVptr->[3] = void(*alpha)();
{
Vbase::m_pVptr = m_pVptr;
void foo(); }
virtual void dir();
virtual void alpha(); V objV;
int b1; objV.do(Vbase* this)
}; {
this->foo(); // this Vbase
// foo(this);
}
7. __declspec(novtable)
class __declspec(novtable) IBase at the code generation level:
{
virtual void foo() = 0; IBase::IBase
virtual void bar() = 0; {
virtual void dir() = 0;
//m_pVptr
}; // will not be initialized at all
class V : public IBase };
{
void foo();
virtual void bar();
virtual void dir();
int b1;
};
class __declspec(novtable) A
{
public:
A() {};
virtual void func1(){ std::cout << 1; }
virtual void func2(){ std::cout << 2; }
virtual void func3(){ std::cout << 3; }
};
class A1 : public A
{
public:
// no func1, func2, or func3
};
8. Default values
#include <iostream> at the code generation level:
using namespace std;
struct VA
{
class A { void* m_pVptr;
};
public:
virtual void Foo(int n = 10) { ?foo@A@@ModuleA@(VA* pThis, 10);
cout << "A::Foo, n = " << n << endl; struct VB
} {
void* m_pVptr;
}; };
class B : public A { ?foo@B@@ModuleB@(VB* pThis, 20);
public:
virtual void Foo(int n = 20) {
cout << "B::Foo, n = " << n << endl; A * pa = new B();
} pa->m_pVptr[fooID]((VA*)&B, XXX);
};
Answer: 10
int main() {
A * pa = new B();
pa->Foo();
return 0;
}
9. Things to Remember
Don't call virtual functions during construction or
destruction, because such calls will never go to a more
derived class than that of the currently executing
constructor or destructor.
10. References
PDF: Working draft, Standard for Programming
Language C++