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 :-)
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ö
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!
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.
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.
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
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?
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
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.
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.
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
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.
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."
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.
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.
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?
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.
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.
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.
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.
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.
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.
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)
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