verwendet. Die verbreitete Bezeichnung wird nicht in ihrer wörtlichen Bedeutung verwendet (in allen OO-Programmiersprachen darf eine Klasse ihre Elemente mehrfach an andere Klassen vererben, aber das ist mit mehrfacher Vererbung nicht gemeint), sondern in einer eher
künstlichen Bedeutung ("ein Klasse K darf mehrere andere Klassen zum vererben ihrer Elemente an K auffordern"). Das englische Verb to inherit bedeutet erben und nicht vererben (vererben heisst im Englischen to leave, to bequeath) und somit sollte man den englischen Fachausdruck multiple inheritance auch nicht mit mehrfacher Vererbung übersetzen. Ein letztes Argument: In OO-Programmiersprachen (Smalltalk, Eiffel, C++, Java) wird immer nur das Erben konkret notiert, an welche Klassen vererbt wird kann höchstens im Kommentar angegeben werden.
1. Mehrfaches Erben, ein einfaches (?) Beispiel
1 // Datei Mehrfach01.cpp
2 // ---3
// Demonstriert einen einfachen Fall von Mehrfachbeerbung. Die Klasse Tief 4
// beerbt die beiden Klassen Links und Rechts. Die Klassennamen Tief, Links 5
// und Rechts sollen die Positionen der Klassen in einem Beerbungsgraphen 6
// deutlich machen.
7
// ---8 #include <iostream>
9
using namespace std;
10
// ---11
class Links { // Eine Basisklasse von Tief ("vererbt an Tief") 12
// Jedes Objekt dieser Klasse stellt eine (rechteckige) Flaeche dar.
13
public:
14
// Ein Standard- und allgemeiner Konstruktor:
15 Links(int laenge=0, int breite=0) { 16
setLaenge(laenge);
17
setBreite(breite);
18
} // Konstruktor Links 19
20
// Methoden:
21 int getFlaeche() const {return laenge * breite;}
22
void setLaenge(int laenge) {
23 // Statt einer negativen Laenge wird 0 genommen:
24
this->laenge = laenge > 0 ? laenge : 0;
25
} // setLaenge 26
27
void setBreite(int breite) {
28 // Statt einer negativen Breite wird 0 genommen:
29 this->breite = (breite > 0) ? breite : 0;
30 } // setBreite 31
32
protected:
33
int laenge;
34 int breite;
class Rechts { // Noch eine Basisklasse von Tief 38
// Jedes Objekt dieser Klasse stellt ein Gewicht dar.
39 public:
40
// Ein (Standard-) Konstruktor:
41 Rechts(double gewicht=0) { 42 setGewicht(gewicht);
43 } // Konstruktor Rechts 44
45 // Methoden:
46 double getGewicht() const {return gewicht;}
47 ---57 class Tief: public Links, public Rechts {
58
// Jedes Objekt dieser Klasse stellt eine Flaeche dar, die mit einem 59
// bestimmten Gewicht belastet ist.
60
public:
61 // Ein Standard- und allgemeiner Konstruktor:
62 Tief(int laenge=0, int breite=0, double gewicht=0) : 63 Links(laenge, breite), Rechts(gewicht) {
cout << "Programm Mehrfach01: Jetzt geht es los!" << endl << endl;
76 Tief otto(12, 5, 150.0);
cout << "otto.getGewicht(): " << otto.getGewicht() << endl;
81
cout << "otto.getFlaeche(): " << otto.getFlaeche() << endl;
82 cout << "otto.druck (): " << otto.druck () << endl << endl;
83
84 cout << "emil.getGewicht(): " << emil.getGewicht() << endl;
85
cout << "emil.getFlaeche(): " << emil.getFlaeche() << endl;
86
cout << "emil.druck (): " << emil.druck () << endl << endl;
87 88
cout << "karl.getGewicht(): " << karl.getGewicht() << endl;
89
cout << "karl.getFlaeche(): " << karl.getFlaeche() << endl;
90
cout << "karl.druck (): " << karl.druck () << endl << endl;
91
92 cout << "Programm Mehrfach01: Das war's erstmal!" << endl;
93
} // main 94
/* ---95 Ausgabe des Programms Mehrfach01:
96 97
Programm Mehrfach01: Jetzt geht es los!
98 99
otto.getGewicht(): 150 100 otto.getFlaeche(): 60 101 otto.druck (): 2.5
102
111 Programm Mehrfach01: Das war's erstmal!
112 --- */
2. Mehrfaches Erben, virtuelle, überladene und überschriebene Methoden
1 // Datei Mehrfach02.cpp 2
// ---3 // Demonstriert mehrfache Beerbung (die Klasse Tief erbt von Links und 4 // Rechts), das Ueberladen und Ueberschreiben von Funktionsnamen (virginia, 5 // nicoline und nikolaus) und eindeutige/mehrdeutige Funktionsaufrufe.
6 // Die Funktion virginia ist virtuell, nicoline und nikolaus sind *nicht*
7 // virtuell, nicoline und nikolaus gibt es jeweils *ohne* Parameter bzw.
8
// mit einem int-Parameter.
9 // Innerhalb einer Klasse genuegt es, wenn gleichnamige Funktionen sich 10 // durch ihre Parameter unterscheiden (siehe nicoline in Klasse Tief). Bei 11 // Funktionen aus verschiedenen Klassen genuegt das nicht (siehe nikolaus 12 // aus Klasse Links und nikolaus aus Klasse Rechts).
13
// ---14
#include <iostream>
15
#include <string>
16 ---32 class Rechts { // Noch eine Basisklasse von Tief
33 public:
class Tief: public Links, public Rechts { 47
52 string nicoline() {
cout << "zt->Links ::virginia(): " << zt->Links ::virginia() << endl;
73
cout << "zt->Rechts::virginia(): " << zt->Rechts::virginia() << endl;
74
81 cout << "zt->Links ::nicoline(): " << zt->Links ::nicoline() << endl;
82 cout << "zt->Rechts::nicoline(): " << zt->Rechts::nicoline() << endl;
83
cout << "zt->Links ::nikolaus(): " << zt->Links ::nikolaus() << endl;
90
cout << "zt->Rechts::nikolaus(1): " << zt->Rechts::nikolaus(5) << endl;
91
92 cout << endl << "nicoline ist ueberladen, aber eindeutig:" << endl;
93 cout << "zt-> nicoline(): " << zt-> nicoline() << endl;
Fehlermeldung des Gnu-Compilers, wenn Zeile 88 kein Kommentar ist:
99 100
Mehrfach02.cpp: In function `int main(...)':
101
Mehrfach02.cpp:88: request for method `nikolaus' is ambiguous 102
---103
Ausgabe des Programms Mehrfach02:
104
105 Mehrfach02: Jetzt geht es los!
106 virginia ist virtuell:
107 zt-> virginia(): virginia aus Klasse Tief!
108
zt->Links ::virginia(): virginia aus Klasse Links!
109
zt->Rechts::virginia(): virginia aus Klasse Rechts!
110
zl-> virginia(): virginia aus Klasse Tief!
111
zr-> virginia(): virginia aus Klasse Tief!
112
113 nicoline ist nicht virtuell:
114 zt-> nicoline(): nicoline aus Klasse Tief!
115
zt->Links ::nicoline(): nicoline aus Klasse Links!
116 zt->Rechts::nicoline(): nicoline aus Klasse Rechts!
117 zl-> nicoline(): nicoline aus Klasse Links!
118 zr-> nicoline(): nicoline aus Klasse Rechts!
119
120 nikolaus ist mehrdeutig:
121 zt->Links ::nikolaus(): nikolaus aus Klasse Links!
122 zt->Rechts::nikolaus(1): nikolaus aus Klasse Rechts!
123
124 nicoline ist ueberladen, aber eindeutig:
125
zt-> nicoline(): nicoline aus Klasse Tief!
126
zt-> nicoline(5): nicoline mit int-Param!
127
--- */
Rein virtuelle Methoden (pure virtual methods) haben eigentlich wenig mit virtuellen Methoden zu tun. Sie entsprechen genau den abstrakten Methoden in Java. Für eine rein virtuelle Methode braucht und darf man keinen Rumpf angeben (stattdessen "= 0"). Eine Klasse, die mindestens eine rein virtuelle Methode enhält, wird dadurch automatisch zu einer abstrakten Klasse. Von einer solchen Klasse kann man keine Objekte vereinbaren, sie kann nur als Oberklasse für weitere Klassendefinitionen dienen. Die erbenden Klassen müssen die geerbten rein virtuellen Methoden mit richtigen Methoden überschreiben, um konkrete Klassen zu sein. Hier ein kleines Beispielpro-gramm:
1 // Datei Virtuell02.cpp
2 /* ---3 Demonstriert eine Klasse Hoch die 2 rein virtuelle Methoden (pure virtual 4 methods) enthaelt. Die Klasse wird dadurch automatisch abstrakt.
5 --- */
6 #include <iostream>
7 using namespace std;
8
// ---9
// Die Klasse Hoch ist abstrakt:
10
class Hoch { 11
protected:
12
int zahl;
13
public:
14
virtual int getZahl() const = 0; // Eine rein virtuelle Methode 15
virtual void setZahl(int zahl) = 0; // Eine rein virtuelle Methode 16
}; // class Hoch 17
// ---18
// Die Klasse Tief erbt von Hoch, implementiert die rein virtuellen 19
// Methoden und ist somit eine konkrete Klasse:
20
class Tief: public Hoch { 21 public:
22
int getZahl() const {return zahl;}
23 void setZahl(int zahl) {this->zahl = zahl;}
24 }; // class Tief
25 // ---26 void main() {
27
cout << "Virtuell02: Jetzt geht es los!" << endl;
28
// Hoch h1;
29
Tief t1;
30
t1.setZahl(17);
31
cout << "t1.getZahl(): " << t1.getZahl() << endl;
32 cout << "Virtuell02: Das war's erstmal!" << endl;
33 } // main
34 /* ---35 Fehlermeldung des Gnu-Compilers, wenn Zeile 28 kein Kommentar ist:
36
37 Virtuell02.cpp:28: cannot declare variable `h1' to be of type `Hoch' 38 Virtuell02.cpp:28: since the following virtual functions are abstract:
39 Virtuell02.cpp:15: void Hoch::setZahl(int) 40 Virtuell02.cpp:14: int Hoch::getZahl() const
41 ---42 Ausgabe des Programms Virtuell02:
43 44
Virtuell02: Jetzt geht es los!
45 t1.getZahl(): 17
46 Virtuell02: Das war's erstmal!
47
--- */