public, protected oder private ableiten

Im einführenden Beispiel des vorigen Abschnitts wurde Laster von Auto public abgeleitet, denn die Definition von Laster begann folgendermaßen:

//...
class Laster: public Auto
{
//...

Im Gegensatz dazu könnte man auch protected ableiten, also so:

//...
class Laster: protected Auto
{
//...
oder auch private:
//...
class Laster: private Auto
{
//...

Worin unterscheiden sich diese Varianten?

Sowohl bei einer public-Ableitung, protected-Ableitung, als auch einer private-Ableitung erbt die ableitende Klasse (hier: Laster) alle Elemente der Basisklasse, und kann -je nach deren Deklaration als private:, protected: oder public: in der Basisklasse- darauf zugreifen. Insoweit besteht kein Unterschied zwischen den Varianten.

Ein Unterschied kommt erst dann zum Vorschein, wenn Anwender der abgeleiteten Klasse (Laster) versuchen, auf Auto-Elemente zu zugreifen:

(In jedem Fall sind in den abgeleiteten Klassen aber alle Elemente der Basisklassen enthalten, auch wenn nur beschränkt darauf zugegriffen werden kann. Eine Klasse kann also durch Ableiten nicht schrumpfen, sondern nur erweitert werden.)

In den meisten Fällen wird man public ableiten. Allerdings kann es sein, daß eine neue Klasse zwar eine Basisklasse sinnvoll intern verwenden kann, aber zu seinem Anwender wiederum eine derart stark geänderte Schnittstelle hat, daß ein Durchgriff auf die Basisklasse nicht mehr sinnvoll ist. Dann wird man private ableiten. (Man sollte sich dann allerdings die Frage stellen, ob wirklich noch eine ,,IST EIN``-Beziehung zwischen den Klassen plausibel ist, oder nicht eher eine ,,HAT EIN``-Beziehung; im letzteren Fall sollte man gar nicht ableiten, sondern statt dessen ein Element vom Typ der zugrunde liegenden Klasse einfügen.)

Wenn man den Durchgriff auf einzelne Elemente dennoch ermöglichen möchte, dann kann man das mit einer Deklaration in der abgeleiteten Klasse etwa in der Art tun:

//...
class Laster: private Auto
{
public:
  Auto::getRaeder;
/...

Angenommen, man hat eine kleine Klasse A mit einem public-, einem protected- und einem private-Teil, dann kann eine Methode der Klasse auf alle Elemente zugreifen:

class A
{
private:
  int privA;

protected:
  int protA;

public:
  int publA;

  virtual void methode( int wert )
  {
    privA = wert; // ok
    protA = wert; // ok
    publA = wert; // ok
  }
};

Davon werden drei Klassen (BprivA, BprotA, BpublA) abgeleitet, je eine private, eine protected und eine public; sowie von diesen dreien wieder je eine CpubB... (und zwar public). In den dabei enthaltenen Methoden sind die unzulässigen Zugriffe auskommentiert:

// von A private erben:
class BprivA: private A
{
public:
  virtual void methode( int wert )
  {
    //privA = wert; // geht nicht, weil private
    protA = wert; // ok
    publA = wert; // ok
  }
};


class CpublBprivA: public BprivA
{
public:
  virtual void methode( int wert )
  {
    //privA = wert; // geht nicht, weil private
    //protA = wert; // geht nicht, weil private von A geerbt
    //publA = wert; // geht nicht, weil private von A geerbt
  }
};


// von A protected erben:
class BprotA: protected A
{
public:
  virtual void methode( int wert )
  {
    //privA = wert; // geht nicht, weil private
    protA = wert; // ok
    publA = wert; // ok
  }
};


class CpublBprotA: public BprotA
{
public:
  virtual void methode( int wert )
  {
    //privA = wert; // geht nicht, weil private
    protA = wert; // ok
    publA = wert; // ok
  }
};


// von A public erben:
class BpublA: public A
{
public:
  virtual void methode( int wert )
  {
    //privA = wert; // geht nicht, weil private
    protA = wert; // ok
    publA = wert; // ok
  }
};

class CpublBpublA: public BpublA
{
public:
  virtual void methode( int wert )
  {
    //privA = wert; // geht nicht, weil private
    protA = wert; // ok
    publA = wert; // ok
  }
};

Die Zugriffsmöglichkeiten über Objekte der einzelnen Klassen sieht man hier (unzulässige Zugriffe sind wieder auskommentiert):

int main( int nargs, char **args )
{
  A einA;
  //einA.privA = 12;, // geht nicht, weil private
  //einA.protA = 12;, // geht nicht, weil protected
  einA.publA = 12; // ok



  BprivA einBprivA;
  //einBprivA.privA = 12; // g.n., w. priv. && priv. von A geerbt
  //einBprivA.protA = 12; // g.n., w. prot. && priv. von A geerbt
  //einBprivA.publA = 12; // g.n., w. priv. von A geerbt

  CpublBprivA einCpublBprivA;
  //einCpublBprivA.privA = 12; // g.n., w. priv. && priv. von A geerbt
  //einCpublBprivA.protA = 12; // g.n., w. prot. && priv. von A geerbt
  //einCpublBprivA.publA = 12; // g.n., w. priv. von A geerbt




  BprotA einBprotA;
  //einBprotA.privA = 12; // g.n., w. priv. && prot. von A geerbt
  //einBprotA.protA = 12; // g.n., w. prot. && prot. von A geerbt
  //einBprotA.publA = 12; // g.n., w. prot. von A geerbt

  CpublBprotA einCpublBprotA;
  //einCpublBprotA.privA = 12; // g.n., w. priv. && prot. von A geerbt
  //einCpublBprotA.protA = 12; // g.n., w. prot. && prot. von A geerbt
  //einCpublBprotA.publA = 12; // g.n., w. prot. von A geerbt




  BpublA einBpublA;
  //einBpublA.privA = 12; // geht nicht, weil private
  //einBpublA.protA = 12; // geht nicht, weil protected
  einBpublA.publA = 12; // ok

  CpublBpublA einCpublBpublA;
  //einCpublBpublA.privA = 12; // g.n., weil private
  //einCpublBpublA.protA = 12; // g.n., weil protected
  einCpublBpublA.publA = 12; // ok
}

Die wesentlichen Zugriffsmöglichkeiten lassen sich auch in einer Tabelle darstellen. Dabei wird wieder von der obigen Klasse A ausgegangen:
Zugriff                  auf privA protA publA
über:      
       
Methode in A: ja ja ja
Objekt vom Typ A: nein nein ja
       
Falls B: private A abgeleitet und C: public B
       
Methode in B: nein ja ja
Objekt vom Typ B: nein nein nein
Methode in C: nein nein nein
Objekt vom Typ C: nein nein nein
       
Falls B: protected A abgeleitet und C: public B
       
Methode in B: nein ja ja
Objekt vom Typ B: nein nein nein
Methode in C: nein ja ja
Objekt vom Typ C: nein nein nein
       
Falls B: public A abgeleitet und C: public B
       
Methode in B: nein ja ja
Objekt vom Typ B: nein nein ja
Methode in C: nein ja ja
Objekt vom Typ C: nein nein ja
       

AnyWare@Wachtler.de