C++-Programmierung/ Objektorientierte Programmierung/ Mehrfachvererbung

Aus Wikibooks
Zur Navigation springen Zur Suche springen


In diesem Abschnitt geht es um mehrfache Vererbung und damit Ableitung von mehreren Basisklassen.

Eine Klasse kann von mehreren Basisklassen erben:

Nuvola-inspired-terminal.svg
 1 class A
 2 {
 3   int x;
 4 
 5   //...
 6 };
 7 
 8 class B 
 9 {
10   double y;
11 
12   //...
13 };
14 
15 class C : public A, public B
16 {
17   char z;
18 
19   //...
20 };

Die Klasse C vereint die Funktionalitäten von A und B und fügt noch etwas hinzu.

Die Idee davon ist, dass verschiedene Funktionalitäten in einer Klasse vereint werden. Im folgenden Beispielprogramm wird dieses Vorgehen dargestellt.

Nuvola-inspired-terminal.svg
 1 #include <string>
 2 #include <iostream>
 3 
 4 class Person
 5 {
 6 	std::string m_strName;
 7 public:
 8 	std::string Name() const { return m_strName; }
 9 	void Name(std::string val) { m_strName = val; }
10 	void Name(const char * val) { m_strName.assign(val); }
11 };
12 
13 class Gehaltsempfaenger
14 {
15 	unsigned int m_nMonatsgehalt;
16 public:
17 	unsigned int Monatsgehalt() const { return m_nMonatsgehalt; }
18 	void Monatsgehalt(unsigned int val) { m_nMonatsgehalt = val; }
19 };
20 
21 class Freizeitbeschaeftigung
22 {
23 	std::string m_strAktion;
24 public:
25 	std::string Aktion() const { return m_strAktion; }
26 	void Aktion(std::string val) { m_strAktion = val; }
27 	void Aktion(const char * val) { m_strAktion.assign(val); }
28 };
29 
30 class Mitarbeiter : 
31 	public Person, 
32 	public Gehaltsempfaenger, 
33 	public Freizeitbeschaeftigung
34 {
35 public:
36 	Mitarbeiter(const char * szName, const unsigned int nMonatsgehalt, const char * szFreizeittaetigkeit)
37 	{ Name(szName); Monatsgehalt(nMonatsgehalt); Aktion(szFreizeittaetigkeit);}
38 	void auszahlenGehalt(void)
39 	{
40 		std::cout << Name() << " bekommt das Monatsgehalt von " 
41 			<< Monatsgehalt() << " Euro ausgezahlt" << std::endl;
42 	}
43 	void entspannenFreizeit(void)
44 	{
45 		std::cout << Name() << " " << Aktion() << std::endl;
46 	}
47 };
48 
49 int main(int argc, char* argv[])
50 {
51 	Mitarbeiter ma1("Christian", 1000, "spielt Skat");
52 	ma1.auszahlenGehalt();
53 	ma1.entspannenFreizeit();
54 	return 0;
55 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 Christian bekommt das Monatsgehalt von 1000 Euro ausgezahlt
2 Christian spielt Skat

Der Vorteil dieser Vorgehensweise ist eine bessere Wiederverwend-barkeit/-ung und eine Kapselung der Schnittstellen.

Schon anhand dieses Beispiels kann eine Person, die eine Freizeitbeschäftigung hat, aber kein Gehalt bekommt, als neue Klasse angelegt werden.

Nuvola-inspired-terminal.svg
1 class Kunde: public Person, public Freizeitbeschaeftigung
2 {
3 	/* ... */ 
4 };

Die Klasse Kunde hat damit die Eigenschaften von Person und Freizeitbeschaeftigung erhalten, aber nicht von Gehaltsempfaenger.

Wichtig ist bei allen Mehrfachvererbungen das Einhalten einer sinnvollen Hierarchie. Was würde passieren, wenn wir von unseren Beispielklassen Kunde und Mitarbeiter ableiten? Lesen Sie daher weiter. Im nächsten Abschnitt wird genauer darauf eingegangen.

Ein weiterer wichtiger Punkt ist die Namensgebung in allen parallel verwendeten Klassen. Würde die Freizeitaktion sowie der Personenname jeweils unter m_strName öffentlich gespeichert, müsste in den abgeleiteten Klassen mit dem Bereichsauflösungsoperator :: auf die passenden Mitgliedsvariablen zugegriffen werden.

Nuvola-inspired-terminal.svg
 1 class Hemd
 2 {
 3 public:
 4 	std::string m_strFarbe;
 5 };
 6 
 7 class Hose
 8 {
 9 public:
10 	std::string m_strFarbe;
11 };
12 
13 class Bekleidung : public Hemd, public Hose
14 {
15 	void ausgeben(void)
16 	{
17 		std::cout << "Hose in " << Hose::m_strFarbe << " Hemd in " << Hemd::m_strFarbe;
18 	}
19 };

Die Verwendung der Mehrfachvererbung ist nicht in jedem Fall einfach zu realisieren, kann schnell unübersichtlich werden und erfordert bei größeren Projekten eine gute Disziplin. Weiterhin sollte sie nicht in übertriebenem Maße verwendet werden. In einigen Fällen ist eine Mitgliedsvariable an Stelle einer Ableitung die bessere Wahl.