Forum: Mikrocontroller und Digitale Elektronik c++ Vererben oder nicht


von Konniemara (Gast)


Lesenswert?

Hallo!

Ich bin Konstantin, neu hier, und hab direkt eine Frage. Bisher habe ich 
mit ein paar Controllerfamilien gearbeitet, aber nur in C und hin und 
wieder Assembler.
Aus Neugier auf c++ und (vor allem dann) weil ich im Moment echt zu 
wenig Zeit habe, bin ich auf Arduino gekommen.
Das System ist ein Roboter, heißt Zumo und dazu gibt es (natürlich) eine 
Library.

So nun die Frage.

Für die Motoren gibt es eine motors lib. Die bietet allerdings nur recht 
rudimentäre Funktionalität. Habe ich schon für meine Bedürfnisse 
erweitert, als da wären geregelte Geradeausfahrt, Streckenfahrt und in 
Ansätzen Kurven. Das funktinoiert so lala und jetzt kommt meine c++ 
Frage.

Eine my_motors Klasseist das Ziel und ich frage mich ob man das so 
machen kann/sollte/könnte dass
a) my_motors von der originalen motors Klasse erbt. Oder
b) ob eine my_motors Klasse ein member von der motors Klasse erhät.

Im Fall a hätte my_motors alle eigenschaften von motors, was ja gewollt 
wäre und nur eine zusatzfunktionalität in Form von den oben erwähnten 
Funktionalitäten. Ist es richtig dass dann die Initialisierung die in 
motors erledigt wird passiert, wenn ich ein Objekt my_motors alege?

Im Fall b würde ein my_motors Objekt was dann nur die neuen Funktionen 
kann jedesmal Funktionen von dem motors Objekt aufrufen.
Hat so was Einflüsse auf das Laufzeitverhalten oder ist quasi nur der 
Inhalt einer Funktion interessant und es ist egal ob die zu einer 
anderen Klasse gehört oder der eigenen.


Ich WEISS es ist etws wirr und ich habe heute Nachmittag zig Anläufe 
gemacht, mein Problem und meine Frage aufzubereiten.
Hätte mir besser gelingen können - hoffentlich versteht der eine oder 
andere mich :-)

von nicht“Gast„ (Gast)


Lesenswert?

Hi,

Bei der Frage ob Member oder vererben, kommst du immer mit der “ist ein 
oder hat ein“ Frage weiter.

In deinem Fall solltest du ableiten.

Den Rest der Fragen würd ich mit ja beantworten. ;)


Tschö

von C++-Coder (Gast)


Lesenswert?

Hi,

ich würde zu b) raten.

Ich gehe davon aus, dass du eine neue Abstraktionsebene hinzufügst und 
deine neue Funktionalität nicht über das bestehende Interface benutzt 
wird. Möglicherweise stellst du später fest, dass du eine andere Klasse 
für die (gleiche) Basisfunktionalität verwenden willst. Mit Vererbung 
würdest du eine sehr starke Bindung eingehen.

Auch wenn jeder mit OOP zuerst Vererbung verbindet: Im allgemeinen 
sollte man sie so sparsam wie möglich einsetzen. Nur wenn du einen 
Client hast, der ohne Kenntnis der (privaten) Unterschiede wahlweise die 
originale oder deine Klasse einsetzen können soll, wäre Vererbung 
angezeigt.

Die Wahl hat aber keinen nennenswerten Einfluss auf das 
Laufzeitverhalten.

Viel Erfolg!

von Peter II (Gast)


Lesenswert?

C++-Coder schrieb:
> Die Wahl hat aber keinen nennenswerten Einfluss auf das
> Laufzeitverhalten.

sicher? Jede Funktion muss man erst ein der neuen Klasse selber 
implementieren. Und dann die passende Funktion von dem anderen Objekt 
aufrufen. Wenn das Objekt dazu eine VTable hat lässt sich das auch nicht 
ohne weiteres wegoptimieren.

Ich bin auch fürs Vererben in diesem Fall.

von PittyJ (Gast)


Lesenswert?

Ich bin für B.
Beim Implementieren kommen immer Aspekte rein, an die man noch nicht 
gedacht hat. Sowas kann ich mit B einfacher lösen. Damit ist man 
flexibler.

Wenn alles fertig ist, kann man immer noch aus B ein A machen. Dann kann 
man entscheiden ob damit alles abgedeckt ist.

von Sheeva P. (sheevaplug)


Lesenswert?

Hi,

ich würde zu a) raten.

Dein Motor ist ja nichts anderes als ein Motor, nur mit ein wenig 
erweiterter Funktionalität. Dein Motor hat ja keinen Motor, sondern 
ist selbst einer -- hier ist also der Beziehungstyp "is-a" angezeigt, 
deswegen natürlich die Vererbung.

HTH,
Sheeva

: Bearbeitet durch User
von Sheeva P. (sheevaplug)


Lesenswert?

C++-Coder schrieb:
> ich würde zu b) raten.
>
> Ich gehe davon aus, dass du eine neue Abstraktionsebene hinzufügst

Der OP beschreibt doch relativ klar, daß er genau das nicht tut. Er hat 
nur ein wenig zusätzliche Funktionalität eingebaut.

> Auch wenn jeder mit OOP zuerst Vererbung verbindet: Im allgemeinen
> sollte man sie so sparsam wie möglich einsetzen.

Diese Aussage kann ich beim besten Willen nicht nachvollziehen. Gerade 
in diesem Falle springt es einem doch geradezu ins Gesicht, daß sein 
Motor nichts anderes als ein erweiterter Motor ist: also Vererbung, was 
sonst?

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Hallo Konstantin,
dein my_motor (my_* sind die mit abstand blödesten Namen, denn das my_ 
hat exakt überhaupt keinen Informations-Inhalt), klingt für mich eher 
nach einem Regler, der auf einem Motor arbeitet. Dem entsprechend könnte 
man auch eine Funktion Kurvenfahrt() implementieren, die dann eben einen 
Motor als Argument nimmt.

Ansonsten sollte man öffentliche (public) Vererbung möglichst Sparsam 
einsetzen. Ist ein my_motor wirklich ein Motor? Oder ist es in Deinem 
Fall nicht evtl. eher ein Regler?

mfg Torsten

von Mark B. (markbrandis)


Lesenswert?

Torsten R. schrieb:
> Hallo Konstantin,
> dein my_motor (my_* sind die mit abstand blödesten Namen, denn das my_
> hat exakt überhaupt keinen Informations-Inhalt), klingt für mich eher
> nach einem Regler, der auf einem Motor arbeitet.

Sowas wie:
my_class, my_car, my_person

sieht man in Beispielen zur OOP hundertfach. Irgendwann muss jemand mal 
damit abgefangen haben, und die anderen haben es wohl einfach übernommen 
anstatt sich bessere Namen auszudenken.

> Dem entsprechend könnte man auch eine Funktion Kurvenfahrt()
> implementieren, die dann eben einen Motor als Argument nimmt.

Nach Möglichkeit bitte nicht deutsch und englisch mischen. Ein my_motor 
ist wohl ein englischer Motor - der hat keine Kurvenfahrt. ;-)

Hm, anscheinend heißt Kurvenfahrt auf englisch "cornering". Wusste ich 
nicht. Wieder was gelernt.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Mark B. schrieb:
> Nach Möglichkeit bitte nicht deutsch und englisch mischen.

kann durchaus in Firmem üblich sein. Es macht kein Sinn deutsche 
Fachbegriffe zu übersetzen oder Get und Set zu übersetzen.

von Mark B. (markbrandis)


Lesenswert?

Peter II schrieb:
> Mark B. schrieb:
>> Nach Möglichkeit bitte nicht deutsch und englisch mischen.
>
> kann durchaus in Firmem üblich sein. Es macht kein Sinn deutsche
> Fachbegriffe zu übersetzen oder Get und Set zu übersetzen.

Ich kenne den Mischmasch aus eigener Berufserfahrung nur zu gut. In 
vielen Fällen dürfte das eher historisch so gewachsen sein als bewusst 
so gewollt.

Nebenbei bemerkt:
Wer OOP richtig macht, braucht weitgehend kein get() und set(). 
Eigentlich sollen Objekte über Nachrichten miteinander kommunizieren.

http://www.javaworld.com/article/2073723/core-java/why-getter-and-setter-methods-are-evil.html

von Peter II (Gast)


Lesenswert?

Mark B. schrieb:
> Nebenbei bemerkt:
> Wer OOP richtig macht, braucht weitgehend kein get() und set().
dann ist wohl 95% alles OOP Libs falsch? Bei Sprachen die Propertys 
haben mag da ja noch gehen.

> Eigentlich sollen Objekte über Nachrichten miteinander kommunizieren.
Das mag ein Ansatz sein, aber ob der immer richtig ist bezweifle ich.

von Mark B. (markbrandis)


Lesenswert?

Peter II schrieb:
> Mark B. schrieb:
>> Nebenbei bemerkt:
>> Wer OOP richtig macht, braucht weitgehend kein get() und set().
> dann ist wohl 95% alles OOP Libs falsch? Bei Sprachen die Propertys
> haben mag da ja noch gehen.

Nur weil etwas oft benutzt wird, bedeutet es nicht dass es so auch gut 
und richtig ist.

Wer seine Klassen per Default immer mit getter- und setter-Methoden 
ausstattet, der hat vermutlich kaum viel Zeit darauf verwendet sich ein 
wirklich gutes Software-Design zu überlegen.

Meinetwegen mögen getter und setter in manchen Fällen sinnvoll sein, 
aber ganz sicher nicht in allen. Es stimmt schon: "Don't ask for the 
information you need to do the work; ask the object that has the 
information to do the work for you."

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Mark B. schrieb:
> Nur weil etwas oft benutzt wird, bedeutet es nicht dass es so auch gut
> und richtig ist.
eigentlich schon, denn wenn es unbrauchbar währe hätte man es durch 
etwas besseres ersetzt.

> Wer seine Klassen per Default immer mit getter- und setter-Methoden
> ausstattet, der hat vermutlich kaum viel Zeit darauf verwendet sich ein
> wirklich gutes Software-Design zu überlegen.
Sauberer Set und Getter sind auch ein gute Design nur halt ein andere 
Design.

von Mark B. (markbrandis)


Lesenswert?

Peter II schrieb:
>> Wer seine Klassen per Default immer mit getter- und setter-Methoden
>> ausstattet, der hat vermutlich kaum viel Zeit darauf verwendet sich ein
>> wirklich gutes Software-Design zu überlegen.
> Sauberer Set und Getter sind auch ein gute Design nur halt ein andere
> Design.

Damit führt man freilich die Datenkapselung ein Stück weit ad absurdum, 
denn man kann die Klasse intern nicht mehr so gut ändern.

von Peter II (Gast)


Lesenswert?

Mark B. schrieb:
> Damit führt man freilich die Datenkapselung ein Stück weit ad absurdum,
> denn man kann die Klasse intern nicht mehr so gut ändern.

warum sollte ich die Klasse dann nicht ändern können? Das Interface muss 
doch nur gleich bleiben?

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Peter II schrieb:
> warum sollte ich die Klasse dann nicht ändern können? Das Interface muss
> doch nur gleich bleiben?

Aber es wird ganz schwierig eine Klasse, die vorher ein "int getA() und 
void setA(int)" hatte, intern irgend wie anders zu implementieren, als 
mit einem int.

von Mark B. (markbrandis)


Lesenswert?

Peter II schrieb:
> Mark B. schrieb:
>> Damit führt man freilich die Datenkapselung ein Stück weit ad absurdum,
>> denn man kann die Klasse intern nicht mehr so gut ändern.
>
> warum sollte ich die Klasse dann nicht ändern können? Das Interface muss
> doch nur gleich bleiben?

Das kann es aber nicht, wenn sich zum Beispiel der Datentyp ändert. Dann 
brauchst Du neue getter() und setter(), und musst sämtliche Stellen im 
Code ändern an denen die alten getter() und setter() Aufrufe standen.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Zum Thema gefällt mir sehr ein älterer Artikel von Herb Sutter (How 
Non-Member Functions Improve Encapsulation): 
http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197

von Uwe (Gast)


Lesenswert?

Vererbung heißt genaugenommen nicht "Erweitern" sondern 
"Spezialisieren" von Klassen.
Deshalb: Wenn MyMotor sich verhält, wie ein allgemeiner Motor, dies aber 
auf spezielle Art und Weise erledigt, und nach außen wie ein beliebiger 
Motor aussehen soll, erbt er von Motor.
Wenn MyMotor aber Funktionen von Motor nur benutzt, um andere oder 
Mehrwert-Funktionen zu realisieren, ist Komposition angesagt.

von Chris F. (chfreund) Benutzerseite


Lesenswert?

Uwe schrieb:
> Vererbung heißt genaugenommen nicht "Erweitern" sondern
> "Spezialisieren" von Klassen.

Und eine Erweiterung ist eine Spezialisierung. Außerdem ist das was Du 
beschreibst eine Aggregation und keine Komposition.
Daher: Daumen Runter.


Eine Vererbung ist eine Art der Implementierung, es muss nicht gleich 
irgendwas sein wo die Basis als Schnittstelle verwendet wird.

Eine Motorklasse die einfach mehr kann und nur den Allgemeinkram vom 
Basismotor übernimmt wird in C++ natürlich als Ableitung implementiert.

von Sven S. (boldie)


Lesenswert?

Ich bin mit C++ weniger am Controller unterwegs, sondern eher in 
größeren Frameworks. Dort kann ich dir sagen, das wir in solchen 
Situationen Vererbung möglichst nicht einsetzen oder nur unter 
Vorsichtsmaßnahmen. Das Problem dabei ist, das wenn eine Änderung in der 
Basis oder der abgeleiteten Klasse passiert es mit zunehmender Größe der 
Verflechtung schwierig wird, die Auswirkungen zu begreifen. In solchen 
Fällen wie du es hier beschreibst nutzten wir das Decorator-Pattern 
(s.a. https://de.wikipedia.org/wiki/Decorator) und kapseln die 
ursprüngliche Komponente vollkommen weg. Dann lässt es sich auch im 
Unittest besser greifen, da man dann die Möglichkeit hat, die Dekorierte 
Klasse gegen einen mock auszuwechseln und nur den Dekorierer zu testen.

von Chris F. (chfreund) Benutzerseite


Lesenswert?

Sven S. schrieb:
> [..] Fällen wie du es hier beschreibst nutzten wir das Decorator-Pattern
> (s.a. https://de.wikipedia.org/wiki/Decorator) und kapseln die
> ursprüngliche Komponente vollkommen weg. Dann lässt es sich auch im

Das kommt immer auf den Anwendungsfall an und wenn ihr bei so einem 
einfachen Konstrukt und bei dem verfügbaren Personal noch ein 
zweistufiges Schnittstellenklassensystem mit einer komplexen 
Arbeitsanweisung darüber legt, dann ist das eine Architekturschwäche.

von Asdf (Gast)


Lesenswert?

Was Du willst ist ja keine Erweiterung des Motors, sondern eine darauf 
aufbauende Funktionalität. Dementsprechend wäre Variante b passender. 
Die Klasse sollte dann aber einen anderen Namen bekommen, z.B. Bewegung 
mit Methoden wie Bewegung::fahreGeradeaus(int geschwindigkeit)

von Konniemara (Gast)


Lesenswert?

Hallo zusammen!

Tut mir leid, dass ich so lange nichts geantwortet habe!

Ich bin im Krankenhaus auf der Kardiologoe gelandet und hatte keinen 
Rechner. Das durchchecken hat einige Tage gedauert.

Ich werde mir eure Antworten in Ruhe durcharbeiten und im Zweifel noch 
mal nachfragen. Und, ja, melde mich nachher direkt an.

Danke an alle

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.