C++-Programmierung/ OOP/ Vererbung
Aus Wikibooks
Inhaltsverzeichnis |
[Bearbeiten] Einleitung
Wenn von Objektorientierung gesprochen wird fällt früher oder später auch das Stichwort Vererbung. Auf dieser Seite lernen Sie anhand eines Beispieles die Grundprinzipien der Vererbung kennen.
[Bearbeiten] Die Ausgangslage
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 strings)
#include<string>
using namespace std;
class Person{
public:
Person(string Name, string Adresse, string Telefon) :m_name(Name), m_addr(Adresse), m_phon(Telfon){}
string getName(){ return m_name; }
string getAddr(){ return m_addr; }
string getPhone(){ return m_phon; }
void info(){ cout << "Name: " << m_name << " Adresse: " << m_addr << " Telfon: " << m_phone << endl; }
private:
string m_name;
string m_addr;
string m_phon;
};
Dies ist natürlich eine sehr minimale Klasse, aber schließlich geht es hier ja auch um die Vererbung :D.
[Bearbeiten] Gemeinsam und doch getrennt
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.
[Bearbeiten] Beispiel
public:
Employee(string Name, string Adresse, string Telefon, int Gehalt, int MitNr):
m_salary(Gehalt),
m_number(MitNr)
:Person(Name,Adresse,Telefon) {}
int getSalary(){ return m_salary; }
int getNumber(){ return m_number; }
private:
int m_salary;
int m_number;
};
[Bearbeiten] Erläuterung des Beispiels
Nun wollen wir uns der Analyse des Beispiels zuwenden um genau zu sehen was passiert ist.
Das wichtigste im Code ist ganz am Anfang: class Employee : public Person. Damit weisen wir den Compiler an, alle Elemente aus Person auch in Employee zu übernehmen (z.B. hat Employee jetzt auch eine info Funktion und eine Membervariable m_name). Eine solche Klasse nennen wir abgeleitet/Kindklasse von Person.
Des weitern 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:
Mit.info();
cout << Mit.getSalary() << endl;
cout << Mit.getName() << endl;
[Bearbeiten] protected
Zum Schluss erweitern 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 Employee 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. Employee. 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.