Hallo zusammen
Beim Recherchieren für das Programmieren von Mikrocontrollern stosse ich
immer wieder auf verschiedene Syntax, wenn es um den Aufruf von
Objektmethoden geht.
Viele Beispiele zeigen folgendes:
Stefan U. schrieb:> Das erste ruft die Methode einer Objektreferenz auf. Das andere ruft die> Methode über einen Zeiger auf, der auf die Objektinstanz zeigt.
Stefan, bitte schreibe mir in diesem Thread nicht mehr weiter. Ich habe
schon einige deiner Kommentare gelesen... Leider meist unverständlich
und zu hochstehend - wie dieser hier. Nichts für ungut.
Michael schrieb:> Stefan, bitte schreibe mir in diesem Thread nicht mehr weiter. Ich habe> schon einige deiner Kommentare gelesen... Leider meist unverständlich
Nicht jedem ist es gegeben, sich auf dein Niveau herunter zu denken.
Eventuell [1] liegt das Problem ja auf deiner Seite.
[1] das Wort steht da als Tribut an die Höflichkeit
N. G. schrieb:
...
> Nun haben wir aber irgenwie einen Zeiger auf diesen Struct (z.B. durch> dynamischen Speicher oder durch einen Parameter):S *pointer;> Bevor man auf die Member-Variable zugreifen kann muss man erst einmal> dereferenzieren:(*var2).x = 42;
Das wäre deutlich klarer, wenn du nicht mitten drin den Namen der
(Pointer-)Variablen ändern würdest. Also besser:
Michael schrieb:> Beim Recherchieren für das Programmieren von Mikrocontrollern stosse ich> immer wieder auf verschiedene Syntax, wenn es um den Aufruf von> Objektmethoden geht.>> Viele Beispiele zeigen folgendes:>> Objekt.Methode();>> manche aber:>> Objekt->Methode();>> Worin liegt hier der Unterschied?
...und für C++: Der Code ist 1. nicht Mikrocontroller-spezifisch und 2.
sind die gegebenen Antworten in dem Sinne unvollständig, dass allein aus
der Syntax nicht auf die Semantik der Code-Schnippel geschlossen werden
kann. Insbesondere bedeuten weder "*Object" noch "Object->" dass
"Object" ein Zeiger sein muss.
Daher kann
Sowohl prefix-* als auch -> können überladen werden, und ob das
tatsächlich der Fall ist kann man nur wissen, wenn man die Definition
von Object kennt.
Und Method braucht auch keine "Methode" zu sein, es kann eine Komponente
sein, deren Klasse () überlädt. Beispiel:
Und all die tollen Antworten nur, um die einzig zielführende Antwort zu
vermeiden:
Nimm dein C/C++ Buch, und lies nach, was es mit den Operatoren und all
dem anderen auf sich hat. Ohne Kenntnis der allereinfachsten und
grundlegenden Konzepte und Syntax einer Programmiersprache versteht man
Quelltexte nunmal nicht.
Ja, dieses Forum ist manchmal Anfängerfeindlich, und ja, das muß
manchmal sein.
Oliver
@gjlayde
Wah.. den () Operator zu überladen dürfte zu dem verwirrendsten Dingen
gehören die man in C++ machen "kann"...
@oliverso
Da ist was dran. Die Geschichte mit den Pointern zählt allerdings klar
zu dem an schwersten zu begreifenden Aspekten von C und C++. Besonders
wenn man von höheren Sprachen kommt.
Dabei ist es weniegr das Konzept an sich von Speicheraddressierung 8was
in Büchern auch breit und lang behandelt wird), sondern die Syntax
selbst.
Alex G. schrieb:> Die Geschichte mit den Pointern zählt allerdings klar zu dem an> schwersten zu begreifenden Aspekten von C und C++.
Hab nie verstanden warum. Man muss sich nur überlegen wie so ein
Speicher strukturiert ist... Und schwerer zu begreifen als z.B.
Metaprogrammierung mit variadischen Templates usw?
Alex G. schrieb:> Wah.. den () Operator zu überladen dürfte zu dem verwirrendsten Dingen> gehören die man in C++ machen "kann"...
Ist aber absolut gängig, um Funktionale zu definieren. Mittlerweile dank
Lambdas etwas weniger.
Alex G. schrieb:> Wah.. den () Operator zu überladen dürfte zu dem verwirrendsten Dingen> gehören die man in C++ machen "kann"...
Schon mal einen ueberladenen []-Operator gesehen? Das ist nicht weniger
verwirrend :D
> die man in C++ machen "kann"...
Gottseidank kann, nicht muss. Ich nutze dieses Feature nur sehr selten.
Wenn ich mir die ganzen langen und teils für mich verwirrenden Antworten
anschaue, war meine erste Antwort wohl doch noch die Beste. Sie sollte
nämlich nur die Stichworte nennen, mit denen man weiter suchen kann.
Alex G. schrieb:> Wah.. den () Operator zu überladen dürfte zu dem verwirrendsten Dingen> gehören die man in C++ machen "kann"...
Kommt darauf an, wofür man es verwendet. Es ist z.B. ein unheimlich
schicker Weg, einem Container einen bounds-check zu verpassen.
> Die Geschichte mit den Pointern zählt allerdings klar> zu dem an schwersten zu begreifenden Aspekten von C und C++
Du solltest hier C und C++ nicht in einen Topf werfen. In C++ braucht
man an sehr vielen Stellen keinen Pointer, wo man in C einen braucht.
Und zwar weil C++ call by reference kann und auch richtige Strings hat.
Nackte Pointer sollte man in einem C++ Programm auch nicht verwenden
(oder brauchen). Dynamische Allozierungen verpackt man besser in
Objekten, dann kann man das Aufräumen auch gleich in den Destruktor
legen. Wenn überhaupt noch Pointer auf der Anwendungsebene, dann
Smartpointer.
Da stimme ich Stefan mal in beiden Punkte zu...
Programmeire C++ allerdings nur für PCs. Eventuell hat man durch solche
Konstrukte, Vorteile in Sachen Geschwindigkeit?
Dr. Sommer schrieb:
Und schwerer zu begreifen als z.B.
> Metaprogrammierung mit variadischen Templates usw?
Wenn man in die herantritt, hat man in der Regel schon einige Monate
intensiver Erfahrung mit C++ und ist abgehärtet :D
Stefan U. schrieb:> Gottseidank kann, nicht muss.
Und wie würdest du dann eine Prädikats-Funktion an std::find_if
übergeben, die sich zusätzliche Dinge merkt? Mit Lambda's geht's
mittlerweile kompakter, aber das ist auch nicht immer geeignet.
Kaj G. schrieb:> Schon mal einen ueberladenen []-Operator gesehen? Das ist nicht weniger> verwirrend :D
Ja, bei std::vector. Funktionier dann genau wie bei Arrays. Super
kompliziert!
Überladene Operatoren sind sicher ein Schock, für Leute, welche aus
einer Sprachecke kommen, welche das nicht kann.
(z.B. ich)
Aber mittlerweile habe ich sie lieben gelernt.
Zum Beispiel ermöglichen sie mir den "Datenfluss" zu betonen. Die
Fixierung auf den Programmfluss spiegelt oftmals nicht das wieder, was
man erreichen möchte.
Gerade, wenn man lang laufende Schleifen/Zeitabläufe aufreißen muss, um
(quasi) Nebenläufigkeiten zu erreichen.
Hier ein Beispiel aus meiner Bastelstube, welches einfach nur
Tastendrücke zählt.
1
voidloop()
2
{
3
counter=flankenerkennung=entprellen=taster;
4
}
Wie gesagt, hier liegt die Betonung auf dem Datenfluss.
Der Programmfluss ist verborgen in den Klassen.
Auch die innere zeitliche Abfolge des entprellens ist unter dem Deckel.
> counter = flankenerkennung = entprellen = taster;
Oha, wie schrecklich!
> Überladene Operatoren sind sicher ein Schock, für Leute, welche aus> einer Sprachecke kommen, welche das nicht kann.
Jawohl
Arduino F. schrieb:> Wie gesagt, hier liegt die Betonung auf dem Datenfluss.> Der Programmfluss ist verborgen in den Klassen.> Auch die innere zeitliche Abfolge des entprellens ist unter dem Deckel.
Macht es dafür Sinn einen Operator so zweck zu entfremden?
Das problem ist eben, wenn jemand anders auf deinen Code da blickt, ohne
diese Hintergründe zu kennen, dann denkt er erstmal "wieso werden da
alle variablen auf den selben Wert gesetzt"?
Sieht sicherlich schön aus, aber wenn man nicht nur für sich selbst
programmeirt, ist das eher ein graus.
Ich hätte für den Zweck eher versucht Java's "Streams" zu immitieren,
damit es in etwa so aussieht:
Weil man alles kann (aber nicht muß), gibt’s ja inzwischen die C++ Core
guidelines (denen man folgen kann, aber nicht muß) Und deren erste Regel
zum Thema Operator-überladen lautet:
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ro-conventional
Der Zuweisungsoperator = sollte grundsätzlich und immer eine Zuweisung
ausführen, in der Form, daß nach a=b a==b true liefert.
Alles andere ist nur was für den Confuscated C Contest.
Oliver
Arduino F. schrieb:> counter = flankenerkennung = entprellen = taster;
Das nennt man neudeutsch "job security" oder?
ungefähr genau so sinnvoll wie extensions.
Nunja...
Muss ja keinem schmecken.
Gibt ja auch durchaus noch andere Notationen!
Meine Klassen sind in der Hinsicht recht vielgesichtig.
Alternative zu:
> counter = flankenerkennung = entprellen = taster;
Dies:
counter(flankenerkennung(entprellen(taster())));
Oder:
counter.doTrigger(flankenerkennung.doTrigger(entprellen.doTrigger(taster
.isHigh())));
Alles das gleiche.
Frisst kein Byte mehr oder weniger.
Alex G. schrieb:> Ich hätte für den Zweck eher versucht Java's "Streams" zu immitieren,> damit es in etwa so aussieht:> counter = taster.entprellen().flankenerkennung().zaehlen();
Da findet ein Fluss von links nach rechts statt. Es werden Referenzen
übergeben.
Macht aus meiner Sicht keinen Sinn hier.
Ich möchte ja Zustände weiter reichen/zuweisen.
An anderer Stelle setze ich das gerne ein!
Auch dazu gerne ein Beispiel:
Alex G. schrieb:> Es geht nicht um Bytes sondern um Leserlichkeit...
Genau!
Und die erste Variante ist (für mich) leserlicher.
Verschachtlungen und Klammern zählen hasse ich wie die Pest.
Wenn man mal kapiert hat, worum es sich dreht, auch für andere.
(die Hoffnung stirbt zuletzt)
Alex G. schrieb:> Es geht nicht um Bytes sondern um Leserlichkeit...
War das nicht eh der Knuth, der den Begriff des "literarischen
Programmierens" geprägt hat?
muss wohl vor C++ gewesen sein ;-)
Arduino F. schrieb:> Alex G. schrieb:>> Ich hätte für den Zweck eher versucht Java's "Streams" zu immitieren,>> damit es in etwa so aussieht:>> counter = taster.entprellen().flankenerkennung().zaehlen();>> Da findet ein Fluss von links nach rechts statt. Es werden Referenzen> übergeben.> Macht aus meiner Sicht keinen Sinn hier.> Ich möchte ja Zustände weiter reichen/zuweisen.
Du hättest da durchaus den .-operator überladen können, wenn du keine
Objektorientierung für diese kleine Sache willst, denn der
offensichtliche Zweck des . - oeprators wäre gleich geblieben.
Beim Üebrladen von =, hast du den erheblich verändert.
Wieso ist das "Weiterreichen von Zuständen" denn deiner Meinung nach
kein Fluss?
Du hast den Taster.
Der Taster wird entprellt.
Auf den entprellten Taster wird Flankenerkennung angewendet.
Die erkannten Flanken werden gezählt.
Arduino F. schrieb:> adc .enable()> .setReference(Adc::REF_11)> .setClockDivisor(Adc::DIV_128)> .setSource(Adc::MUX_THERMO)> .setCallBack(adcCallBack)> .enableAutoTrigger()> .setTrigger(Adc::TRIG_FREERUNNING)> .enableIrq()> .startConversion();
Hier versteht jeder sofort was abgeht.
Arduino F. schrieb:> counter = flankenerkennung = entprellen = taster;
und hier versteht (wenn überhaupt) nur derjenige der es geschrieben hat
was abgeht. Bitte nimm es nicht persönlich aber ich sehe vor allem in
der Arduino-Welt die kriminellsten Dinger wenn es um das überladen von
Operatoren oder Funktionen geht. Das es funktioniert ist ja gar keine
Frage aber der Code taugt dann nur noch für Obfuscation-Contests.
Alex G. schrieb:> Du hättest da durchaus den .-operator überladen können, wenn du keine> Objektorientierung für diese kleine Sache willst, denn der> offensichtliche Zweck des . - oeprators wäre gleich geblieben.> Beim Üebrladen von =, hast du den erheblich verändert.
Da hätte ich doch mal gerne eine Vorführung gesehen!
Ein Beispiel.
Habe mir die überladbaren Operatoren ausführlich angesehen, aber der .
ist mir dabei noch nicht unter gekommen.
http://en.cppreference.com/w/cpp/language/operators gibt das nicht her.
Und meine beiden C++ Bücher auch nicht.
Der Compiler schreit bei dem Versuch:
> error: expected type-specifier before '.' token
ok, ok, da mag ich noch was falsch gemacht haben.
Was solls, ist ein Grund, nochmal auf die Suche zu gehen.....
---
2 Probleme sehe ich jetzt schon leuchten...
1. Bisher brauche ich für den Taster kein Byte Ram. Die definierte
Instanz wird vollständig weg optimiert. Es bleibt nur die Inline
Funktionalität im resultierenden Code erhalten. Ob mir das dann so
erhalten bleibt? Wenn ich da mit Zeigern und Referenzen spielen muss?
2. Der Dot Operator würde mir die Initialisierung kaputt machen.
taster.init(). Ohne Extrawürste wirds dann nicht gehen.
Wenn sich die beiden Sorgen ohne Probleme aushebeln lassen, wäre ich
sehr erfreut. Muss es aber erst sehen und fühlen.
Ob ich
> counter = flankenerkennung = entprellen = taster
oder
> taster.entprellen.flankenerkennung.counter
schreibe ist mir echt egal...
Alex G. schrieb:> Oops, mein Fehler. Der Punkt ist tatsächlich eine Ausnahme.> Geht doch nicht alls in C++.
Danke, für die Rückmeldung!
Und ich dachte schon...
Dann werde ich erstmal den Zuweisungsoperator beibehalten. Denn die
anderen Operatoren sind noch "absurder" an der Stelle.
Werde dann warten, bis C++ mir den <- Operator erlaubt
counter<-flankenerkennung<-entprellen<-taster;
Arduino F. schrieb:> Werde dann warten, bis C++ mir den <- Operator erlaubt>> counter<-flankenerkennung<-entprellen<-taster;
Und warum nicht den Schiebeoperator '<<'? Würde sogar etwas Sinn
ergeben.
MfG,
Andreas
> ich würde den §-Operator vorschlagen
Was macht man damit?
text=GrundGesetz§3.4;
> Und warum nicht den Schiebeoperator '<<'?
Das war auch mein spontaner Einfall dazu, schließlich wird der auch bei
std::cout "missbraucht".
Stefan U. schrieb:>> ich würde den §-Operator vorschlagen>> Was macht man damit?>> text=GrundGesetz§3.4;
Die Leute in ihrem Bastelkeller einsperren, und nur ja nicht auf den
Arbeitsmarkt lassen?
Stefan U. schrieb:>>> Und warum nicht den Schiebeoperator '<<'?>> Das war auch mein spontaner Einfall dazu, schließlich wird der auch bei> std::cout "missbraucht".
Und auch in Qt-Containern:
Andreas M. schrieb:> Und warum nicht den Schiebeoperator '<<'? Würde sogar etwas Sinn> ergeben.
Naja....
Habe ich drüber nachgedacht!
Und auch implementiert gehabt.
Würde dann im Extremfall zu so einem Bild führen:
Deine operator overloads verstoßen allesamt gegen das "principle of
least astonishment".
https://en.wikipedia.org/wiki/Principle_of_least_astonishment
Für Außenstehende, für die deine Klassen alle eine Blackbox darstellen,
ist in keinsterweiße nachvollziehbar was du mit dem assignment
bezweckst.
Vincent H. schrieb:> Deine operator overloads verstoßen allesamt gegen das "principle of> least astonishment".
Was aber nichts daran ändert, dass man die Semantik der vom OP gezeigten
2 Codezeilen nicht wissen kann, ohne die Definition der
zugrundeliegenden Deklarationen und Definitionen zu kennen.
Ich würd auch jetzt nicht sagen, dass "->" zu überladen weniger oder
mehr überraschend ist als die Default-Bedeutung von "->".
Dito für andere Features wie Ableitung etc.
> Ich würd auch jetzt nicht sagen, dass "->" zu überladen weniger oder> mehr überraschend ist als die Default-Bedeutung von "->".
Wohl wahr, einen Schönheitswettbewerb würde C++ nie gewinnen.
Stefan U. schrieb:> einen Schönheitswettbewerb würde C++ nie gewinnen.
Mir wäre ja auch Forth recht...
Aber das fühlt sich auf einer Von Neumann Maschine wohler.
Und irgendein Massenspeicher um das Image zu laden wäre auch schön.
Obwohl, einen "Schönheitswettbewerb" gewinnt man damit auch nicht.
Aber zumindest kann man sich da einen <- Operator bauen (ohne dass man
erschlagen wird), wenn man meint einen zu brauchen.