class Vehicle
{
public:
Vehicle(char* regnum)
: myRegNum(strdup(regnum))
{}
~Vehicle(void)
{ delete[] myRegNum; }
void Describe(void)
{
cout << "Unknown vehicle, registration "
<< myRegNum << endl;
}
protected:
char* myRegNum;
};
class Car : public Vehicle
{
public:
Car(char* make, char* regnum)
: Vehicle(regnum), myMake( strdup(make) )
{}
~Car(void)
{ delete[] myMake; }
void Describe(void)
{
cout << "Car (" << myMake
<< "), registration "
<< myRegNum << endl;
}
protected:
char* myMake;
};
Vehicle* vp1 = new Vehicle ("SGI 987");
Vehicle* vp2 = new Car ("Jaguar","XJS 012");
vp1->Describe(); // PRINTS "Unknown vehicle....."
vp2->Describe(); // PRINTS "Unknown vehicle....."
Vehicle v1 ("SGI 987");
Car c1 ("Jaguar","XJS 012");
Vehicle& vr1 = v1;
Vehicle& vr2 = c1;
vr1.Describe(); // PRINTS "Unknown vehicle....."
vr2.Describe(); // PRINTS "Unknown vehicle....."
Describe()
member¤ function to call, it selects
according to the type of the pointer (Vehicle*
or Vehicle&
in both cases), rather than the type
of the object being pointed at or referred to (Vehicle
or
Car
)
Describe()
member¤ are
dispatched to Vehicle::Describe()
, even when the
pointer of reference¤ actually points to a Car
object!
virtual
keyword
virtual
keyword is called a virtual function¤
class Vehicle
{
public:
Vehicle(char* regnum)
: myRegNum(strdup(regnum))
{}
~Vehicle(void)
{ delete[] myRegNum; }
virtual void Describe(void)
{
cout << "Unknown vehicle, registration "
<< myRegNum << endl;
}
protected:
char* myRegNum;
};
class Car : public Vehicle
{
public:
Car(char* make, char* regnum)
: Vehicle(regnum), myMake( strdup(make) )
{}
~Car(void)
{ delete[] myMake; }
virtual void Describe(void)
{
cout << "Car (" << myMake
<< "), registration "
<< myRegNum << endl;
}
protected:
char* myMake;
};
Vehicle* vp1 = new Car ("Jaguar","XJS 012");
Vehicle* vp2 = new Vehicle ("SGI 987");
Vehicle* vp3 = new Vehicle ("ABC 123");
vp1->Describe(); // PRINTS "Car (Jaguar)....."
vp2->Describe(); // PRINTS "Unknown vehicle....."
vp3->Describe(); // PRINTS "Unknown vehicle....."
vp1->Describe()
is replaced with following:
(*((vp1->_vtab)[0]))()
vp1->_vtab
locates a special "secret" data
member
¤¤
of the object pointed to by vp1
. This data
member¤¤
is automatically present in all objects with at least one virtual
function¤.
It points to a class¤-specific
table of function pointers (known as the classe's vtable)(vp1->_vtab)[0]
locates the first element of the object's
class¤'s
vtable (the one corresponding to the first virtual function¤
- Describe()
). That element is a function pointer to the appropriate Describe()
member¤
function.(*((vp1->_vtab)[0]))()
dereferences¤
the function pointer and calls the functionvp1
, vp2
, and vp3
as follows:
Vehicle* vp4 = new Car ("Aston Martin", "JB 007");
// AND LATER...
delete vp4;
class Vehicle
{
public:
Vehicle(char* regnum)
: myRegNum(strdup(regnum))
{}
virtual ~Vehicle(void)
{ delete[] myRegNum; }
virtual void Describe(void)
{
cout << "Unknown vehicle, registration "
<< myRegNum << endl;
}
protected:
char* myRegNum;
};
class Car : public Vehicle
{
public:
Car(char* make, char* regnum)
: Vehicle(regnum), myMake( strdup(make) )
{}
virtual ~Car(void)
{ delete[] myMake; }
virtual void Describe(void)
{ cout << "Car (" << myMake
<< "), registration "
<< myRegNum << endl;
}
protected:
char* myMake;
};
Vehicle* vp4 = new Car ("Jaguar","XJS 012");
delete vp4; // CALLS Car::~Car()
// (WHICH THEN CALLS Vehicle::~Vehicle())