Hallo steckl,
Abstraktion ist doch nur bei Vererbung, oder?
Abstraktion bedeutet erstmal nur, von einer konkreten Sache zu einer Allgemeinen zu kommen. Vererbung ist eine Möglichkeit, Abstraktion im Programmcode nachzubilden.
In deinem Taschenrechner-Beispiel könntest du dir z.B. ein Display vorstellen, das grüne Ziffern im LED-Design auf schwarzem Grund hast, eines für eine Textausgabe auf der Konsole und noch weitere. Wenn du jetzt überlegst, welche Eigenschaften alle Displays (und nicht nur die, die du dir gerade vorgestellt hast, sondern alle möglichen Displays) gemeinsam haben, hast du von konkreten Displaytypen auf die abstrakte "Idee" eines Displays abstrahiert.
Du könntest dies jetzt mit einer Klasse AbstractDisplay von der die verschiedenen Display-Typen als einzelne Klassen abgeleitet werden nachbilden.
Macht es Sinn, die ganze Rechner-Klasse auf das Display zu vererben?
Oder lieber eine gemeinsame Super-Klasse, von der dann beide das Ergebnis erben?
Weder noch. Zwar braucht man beim Abstrahieren nicht bei einem abstrakten Display stehen zu bleiben, sondern kann das beliebig weiter führen, bis man eine Klasse hat, die die gemeinsamen Eigenschaften eines Taschenrechners und eines Displays abbildet. In Java beispielsweise wird dies auf die Spitze getrieben, indem es eine Klasse Object gibt, von der letztendlich alle anderen Klassen abgeleitet sind. Ob es ein C++-Äquivalent dazu gibt, kann ich dir leider nicht sagen.
Ableitung von einer gemeinsamen Elternklasse ist aber nicht die einzige Beziehung, in der zwei Klassen zueinander stehen können. Wenn die Klasse Taschenrechner beispielsweise ein Display-Objekt als Eigenschaft hat, besteht zwischen den beiden Klassen auch eine Beziehung.
Die Kapselung würde in dem Fall also auch für eine gute Austauschbarkeit sorgen.
Kapselung heisst in diesem Fall nur die Rechtevergabe mit Public, Private oder Protected, oder?
Kapselung bedeutet, dass du die Art und Weise, wie das Programmmodul intern funktioniert versteckst, und dem Programmierer, der dieses Modul einbindet nur sagst, wie er die Methoden aufrufen soll, die er braucht, um dieses Modul zu verwenden. Die Schlüsselwörter private und protected helfen bei der Einhaltung dieser Vorgehensweise, indem Sie verbieten, andere als die für den Zugriff von außen vorgesehenen Methoden zu verwenden.
Das bedeutet im Endeffekt, dass due nicht gegen eine konkrete Implementierung, sondern nur gegen die Beschreibung der Außenansicht einer Implementierung implementierst. Eine solche Beschreibung nennt man Schnittstelle.
Bei deinem Taschenrechner ließe sich die Klasse AbstractDisplay als Schnittstelle ansehen. Indem du in dem Taschenrechner nur diese Klasse verwendest, ignorierst du automatisch diejenigen Eigenschaften konkreter Displaytypen, die für die Einbindung nicht relevant sind. Da auch alle Display-Arten, da sie als Unterklasse von AbstractDisplay abgeleitet sind, die Methoden der Klasse AbstractDisplay teilen, ist es später zudem problemlos möglich eine Art Display gegen eine andere auszutauschen, ohne dass der Taschenrechner-Code geändert werden müsste.
Schöne Grüße,
Johannes