Inheritance is a way you can build hierarchies or relationships from classes, imagine a 'vehicle' class with several base functions, 'start' and 'stop' then imagine a derived or inherited class called 'car' that will have access to the original 'vehicle' functions of stop and start, but will add specialised functions, for example 'accelerate' 'brake' and 'change gear'. This is a good example of inheritance, derivation and specialisation.
The syntax to derive a class is:
class car : public vehicle
Simple enough, the following example shows a derived 'Car' class, and demonstrates how to use a derived object as well as the relationship between the constructors:
enum MAKE {Ford, Toyota, Vauxhall, Honda, Volvo};
class Vehicle
{
public:
Vehicle() { cout << "Vehicle constructed" << endl; }
~Vehicle() { cout << "Vehicle deconstructed" << endl; }
int GetYear() { cout << itsYear << endl; return itsYear; }
int SetYear(int year) {return itsYear = year; }
void Start() { cout << "vehicle started" << endl; }
void Stop() { cout << "vehicle stopped" << endl; };
protected:
int itsYear;
};
class Car : public Vehicle
{
public:
Car() { cout << "Car constructed" << endl; }
~Car() { cout << "Car deconstructed" << endl; }
MAKE GetMake() { cout << itsMake << endl; return itsMake; }
void SetMake(MAKE make) {itsMake = make; }
protected:
MAKE itsMake;
};
int main()
{
Car myCar;
myCar.SetYear(1993);
myCar.SetMake(Toyota);
myCar.Start();
myCar.GetYear();
myCar.GetMake();
myCar.Stop();
return 0;
}
Pleasant, an object of the 'Car' class has access to the start/stop functions of the vehicle class, through inheritance. Taking polymorphism to the next step, we can assign a pointer to our base class (Vehicle) and create an object of our derived class with it (Car).
Vehicle* pVehicle = new Car;
This will create a car object on the heap. This is what polymorphism is all about, you can create a shedload of objects but they could all access a virtual function (lets say accelerate) if you were to create a pointer and assign all the objects to that pointer, you could call the virtual accelerate function without any regard for scope etc, to demonstrate;
class Vehicle
{
public:
Vehicle():itsYear(1984) { cout << "Vehicle constructed" << endl; }
~Vehicle() { cout << "Vehicle deconstructed" << endl; }
void Start() { cout << "Vehicle starts" << endl; }
void Stop() { cout << "Vehicle stops" << endl; }
virtual void Accelerate() { cout << "Vehicle accelerates" << endl; }
protected:
int itsYear;
};
class Car : public Vehicle
{
public:
Car() { cout << "Car constructed" << endl; }
~Car() { cout
<< "Car deconstructed" << endl; }
void Accelerate() { cout << "Car Accelerates" << endl; }
};
int main()
{
Vehicle *pCar = new Car;
pCar->Start();
pCar->Accelerate();
pCar->Stop();
return 0;
}
By declaring Vehicle's Accelerate function as virtual basically indicates that at some point this class will be derived from and that this function will get overridden, in main() we create a pointer to a vehicle but assign it the address of a car, because a car is a vehicle, thats fine with the compiler, then the pointer is used to call the accelerate function, because accelerate is virtual, the overriding function in the car class is invoked, pleasant, note this only works via pointers and references, passing it by value wont work.
As I've been demonstrating by adding output statements to the constructors, to construct an object in a derived class involves first calling the base constructor, then the derived constructor. When a virtual function is invoked in an object, it must keep track of the function, to do this a compiler will build whats known as a virtual function table, one is created for each type, each object of that type keeps whats known as a vptr (virtual table pointer) which points to that table.
This article was originally written by Pigsbig78 |