C++-Programmierung/ Objektorientierte Programmierung/ Vererbung
Einleitung
[Bearbeiten]Wenn von Objektorientierung gesprochen wird, fällt früher oder später auch das Stichwort Vererbung. Auf dieser Seite lernen Sie anhand eines Beispiels die Grundprinzipien der Vererbung kennen.
Die Ausgangslage
[Bearbeiten]Stellen wir uns vor, dass wir in einer Firma arbeiten und in einem Programm sämtliche Personen verwalten, die mit dieser Firma in einer Beziehung stehen.
Über jede Person sind folgende Daten auf jeden Fall bekannt: Name, Adresse, Telefonnummer.
Um alles zusammenzufassen, haben wir uns eine Klasse geschrieben, mit deren Hilfe wir eine einzelne Person verwalten können:
(Aus Gründen der Einfachheit benutzen wir string
s)
#include<iostream>
#include<string>
using namespace std;
class Person{
public:
Person(string Name, string Adresse, string Telefon) :m_name(Name), m_adr(Adresse), m_tel(Telefon){}
string getName(){ return m_name; }
string getAdr(){ return m_adr; }
string getTel(){ return m_tel; }
void info(){ cout << "Name: " << m_name << " Adresse: " << m_adr << " Telefon: " << m_tel << endl; }
private:
string m_name;
string m_adr;
string m_tel;
};
Dies ist natürlich eine sehr minimale Klasse, aber schließlich geht es hier ja auch um die Vererbung.
Gemeinsam und doch getrennt
[Bearbeiten]Die obige Klasse funktioniert ja eigentlich ganz gut, nur gibt es ein kleines Problem. In unserer Firma gibt es Mitarbeiter, Zulieferer, Kunden, Chefs, ... . Diese sind zwar alle Personen, sie haben jedoch jeweils noch zusätzliche Attribute (z. B. ein Mitarbeiter hat einen Lohn, während ein Kunde eine KundenNr. hat). Jetzt könnten wir natürlich für jeden unterschiedlichen Typ eine eigene Klasse schreiben, den bereits vorhanden Code der Klasse Person
hineinkopieren und schließlich die entsprechenden Erweiterungen vornehmen.
Dieser Ansatz hat jedoch einige Probleme:
- Er ist unübersichtlich.
- Es kann leicht zu Kopierfehlern kommen.
- Soll
Person
geändert werden, so muss jede Klasse einzeln bearbeitet werden.
Zum Glück bietet uns C++ aber ein mächtiges Hilfsmittel in Form der Vererbung. Anstatt alles zu kopieren, können wir den Compiler anweisen, die Klasse Person
als Grundlage zu verwenden. Dies wird durch ein Beispiel klarer.
Beispiel
[Bearbeiten]class Mitarbeiter : public Person
{
public:
Mitarbeiter(string Name, string Adresse, string Telefon, int Gehalt, int MANr):Person(Name,Adresse,Telefon),
m_gehalt(Gehalt), m_nummer(MANr) {}
int getGehalt(){ return m_gehalt; }
int getNummer(){ return m_nummer; }
private:
int m_gehalt;
int m_nummer;
};
Erläuterung des Beispiels
[Bearbeiten]Nun wollen wir uns der Analyse des Beispiels zuwenden, um genau zu sehen, was passiert ist.
Das wichtigste im Code steht ganz am Anfang: class Mitarbeiter : public Person
. Damit weisen wir den Compiler an, alle Elemente aus Person
auch in Mitarbeiter
zu übernehmen (z.B. hat Mitarbeiter
jetzt auch eine info-Funktion und eine Membervariable m_name
). Eine solche Klasse nennen wir abgeleitet/Kindklasse von Person
.
Des Weiteren rufen wir im Konstruktor auch den Konstruktor von Person
auf. Wir sparen uns also sogar diesen Code.
Benutzen können wir die Klasse wie gewohnt, mit der Ausnahme, dass wir jetzt auch alle Methoden von Person
aufrufen können:
Mitarbeiter Mit("Erika Mustermann", "Heidestraße 17, Köln", "123/454", 4523, 12344209);
Mit.info();
cout << Mit.getGehalt() << endl;
cout << Mit.getName() << endl;
Warum wir das Schlüsselwort public
verwenden, wird im Kapitel „Private und geschützte Vererbung“ erklärt.
protected
[Bearbeiten]Zum Schluss werden wir noch das Prinzip der Datenkapselung auf die Vererbung erweitern. Bis jetzt kennen wir die Schlüsselwörter public
und private
. Machen wir folgendes Experiment: Schreiben Sie eine neue Membermethode von Mitarbeiter
und versuchen Sie auf m_name
aus der Person
-Klasse zuzugreifen. Der Compiler wird einen Fehler ausgeben. Warum?
m_name
wurde in der Person
-Klasse als private
deklariert, das heißt, es kann nur von Objekten dieser Klasse angesprochen werden, nicht aber von abgeleiteten Klassen wie z. B. Mitarbeiter
. Um zu vermeiden, dass wir m_name
als public
deklarieren müssen, gibt es protected
. Es verhält sich ähnlich wie private
, mit dem Unterschied, dass auch Objekte von Kindklassen auf mit diesem Schlüsselwort versehene Member zugreifen können.