Inheritance

Classes afleiden uit andere classes

C++ biedt de mogelijkheid classes af te leiden uit andere classes. Dat noemen we inheritance. Een afgeleide class (derived class) krijgt dan alle eigenschappen van de class waar die van afgeleid is: de base class. Je kunt zeggen dat een derived class een speciaal geval is van een base class.

Je kunt zeggen "Een vierkant is een Figuur" en ook "Een Driehoek is een Figuur". Figuur is de parent class van Vierkant, Driehoek etc. Een Figuur kun je niet tekenen zo lang je niet weet hoe die eruit ziet, maar je kunt wel bijvoorbeeld zijn basispositie, snelheid en basisgrootte instellen.

Elk van de afgeleide classes erft de basispositie, snelheid en basisgrootte van Figuur en voegt daaraan de specifieke vorm toe zodat hij ook getekend kan worden.

Een subclass voegt dus alleen die elementen toe die hem onderscheiden van de base class en andere subclasses.

Wat betekent inheritance voor de objecten ?

Een class op zich doet niks. Het is alleen een beschrijving voor het maken van objecten. Als je een object maakt van een bepaalde klasse dan krijgt het object de eigenschappen die in die klasse zijn vastgelegd. Wanneer we een object maken van een derived class krijgt het object eigenschappen van de base class en eventueel extra eigenschappen die in de beschrijving van de derived class zijn toegevoegd. Maar we hebben het nog steeds over één object.

Nogmaals (want dit is belangrijk) : een object van een afgeleide class heeft een base class deel en een derived class deel in zich. Het is echter maar één object.

Constructoren

Constructoren worden niet geërfd.

Een default constructor is een constructor die geen parameters nodig heeft, bijvoorbeeld


class myClass
{
  void myClass(); // default constructor
  ....

Als je zelf geen default constructor maakt zal de compiler er een maken die de geheugenruimte voor het object aanvraagt, de default constructoren van de te maken member-objecten aanroept, evenals de default constructoren van de base class (of classes) van de betreffende class. Dit wordt wel een implicit constructor genoemd.

Base class constructor for derived class object

Bij het maken van een object van een afgeleide class wordt als eerste de constructor uit het base-class gedeelte aangeroepen en daarna de constructor van de afgeleide class. Als je niks aangeeft wordt de default constructor van de base class gebruikt, dus de constructor zonder parameters, of als die niet bestaat de implicit constructor.
Soms wil je niet de default constructor van de base class gebruiken maar een constructor met parameters, zodat je bij de constructie van het object extra eigenschappen kunt aangeven. In dat geval zet je die (niet-default) base class constructor bij de init-lijst van de constructor van de afgeleide class zoals in het voorbeeld hieronder.
Hier is SpecialBox de class die afgeleid is van GenericBox. Normaal gezien zou de constructor GenericBox::GenericBox() uitgevoerd worden, maar in het voorbeeld wil je parameters x en y meegeven bij de constructie van het object.
De constructor SpecialBox::SpecialBox(x,y,z) roept eerst de constructor GenericBox(x,y) aan voordat de code depth(z) wordt uitgevoerd.

SpecialBox::SpecialBox(x,y,z) : GenericBox(x,y)
{
  depth(z);
}

Op zich is het wel mooi en duidelijk om altijd aan te geven welke base class constructor je wilt aanroepen, zelfs als je geen afwijkende parameters wilt meegeven.

SpecialBox::SpecialBox(x,y,z) : GenericBox()
{
}

Privileges: public, private en protected

Als je niks opgeeft zijn alle class members private. Een class met alleen private members zal niet veel doen want je kunt dan alleen de default constructor gebruiken en niet je eigen constructor maken omdat een (niet-default) constructor altijd public moet zijn. Bovendien kun je van buiten af de toestand niet beinvloeden. Zo'n class is hooguit nuttig om andere classes van af te leiden.

Ik geef er de voorkeur aan te beginnen met de public members: die vormen de interface. Dan de private members: daarmee maak je de interne implementatie van de class.

Wanneer je een afgeleide class toegang wilt geven tot private members van de base class dan kun je protected gebruiken. Voor de buitenwereld (anders dan de class zelf en zijn afgeleide classes) werkt dat gewoon als private.

Met 'friend' kun je privileges uitdelen.

Public inheritance vs private inheritance

See also: http://www.cplusplus.com/forum/beginner/12899
class Parent
{
public:
  virtual void CallChild() = 0;

  void DoStuff()
  {
    CallChild();  // calls a function in the child class
  }
};

class Child : private Parent
{
public:
  virtual void CallChild() { /*...*/ }
};
Note: in most cases it's better to use public inheritance combined with composition (say object 'has' another object within it).

Encapsulation

Abstract base class

Van een class waarbij de constructoren protected zijn kun je geen objecten maken, maar wel classes afleiden waar je wel objecten van kunt maken. Zo'n class met alleen protected constructoren zou je een abstracte class kunnen noemen. Een abstract base class kan ook ontstaan door pure virtual functies, zoals besproken in het stukje over polymorfisme.

Hier staan enkele voorbeelden van inheritance.

Volgorde van aanroepen constructors

Het maken van een object van een afgeleide class gebeurt in deze volgorde: eerst het base class gedeelte met al zijn members, daarna pas het derived-class deel. In meer detail:
Voorbeeld:

De code

Een header file is de interface

Voor inheritance hoef je de sources niet te hebben, alleen de interface (header files) en de gecompileerde file (object-file) of een library, wat eigenlijk ook een verzameling gecompileerde files is.