const vorne: bezieht sich auf die retournierten Daten.
const hinten: bezieht sich auf die Funktion. Eine Funktion, die den
Zustand des Objekts nicht verändert (=> mögliche Optimierung).
> const vec3 operator+( vec3 &e )
liefer ein vec3 zurück der aber const ist, er darf/kann also nicht
veändert werden. Macht aber nicht so viel sinn, wird im zusammenhang mit
referenz verwenden.
z.b.
1
constvec3&operator+(vec3&e)
damit verhindert man, das jemand ein objekt was man nur als Referenz
rausgibt ändert.
Und was ist der unterschied zwischen dem und wenn ich es erst am schluss
schreibe?
vec3 operator+( vec3 &e ) const
hier sagt das const, das das objekt von der methode nicht durch den
methoden aufruf geändert wird. (gibt auch wieder ausnahmen (mutable)
Kann man auch "const" weglassen?
kann man, aber ist sollte man nicht.
Beide gleich: konstante Zeiger. In zweiten Fall als Referenz darauf.
Die Syntax von Typdeklarationen in C und infolgedessen C++ ist
hoffnungslos verhunzt, da ist nichts mehr zu retten. Daher diese
Konfusion. Mit Googles Go bin ich erstmals einer in syntaktischer
Tradition von C stehenden Sprache begegnet, die sich davon etwas ablöst.
A. K. schrieb:> Beide gleich: konstante Zeiger. In zweiten Fall als Referenz darauf.>> Die Syntax von Typdeklarationen in C und infolgedessen C++ ist> hoffnungslos verhunzt, da ist nichts mehr zu retten.
Na komm, so schwer ist das in diesem Fall auch nicht. const bezieht sich
immer auf das, was direkt links davon steht, mit einer Ausnahme: Wenn
links nichts mehr ist, bezieht es sich auf das, was direkt rechts davon
steht.
Richtig lustig wird's eigentlich erst, wenn man Funktionen deklariert,
die mit Funktionszeigern arbeitet. Ein gerne genommenes Beispiel ist die
Standard-Funktion signal(), deren Deklaration so aussieht:
> Mit Googles Go bin ich erstmals einer in syntaktischer Tradition von C> stehenden Sprache begegnet, die sich davon etwas ablöst.
Bei Java hat man das gelöst, indem man einfach die Hälfte weggelassen
hat.
Rolf Magnus schrieb:> Na komm, so schwer ist das in diesem Fall auch nicht. const bezieht sich> immer auf das, was direkt links davon steht, mit einer Ausnahme: Wenn> links nichts mehr ist, bezieht es sich auf das, was direkt rechts davon> steht.
Ich hätte eher gesagt, const bezieht sich in C immer auf das, was direkt
rechts daneben steht, und das ohne Ausnahme, also noch einfacher.
In C++ gibt es noch das const rechts neben einer Funktionsdeklaration.
Da kann diese Regel natürlich nicht gelten, aber hier hat const auch
eine ganz andere Bedeutung, weswegen man es sich getrennt merken muss.
Da wurde einfach nur Schlüsselwortrecycling gemacht, ähnlich wie bei
static, wenn es außerhalb eines Funktionsrumpfs benutzt wird.
Eigentlich ist die Typdeklaration in C und C++ ziemlich logisch und
konsistent, wenn man das Prinzip erst mal kapiert hat. Am besten ist es,
man arbeitet sich von innen, beginnend mit dem deklarierten Variablen-
namen, nach außen.
Yalu X. schrieb:> Rolf Magnus schrieb:>> Na komm, so schwer ist das in diesem Fall auch nicht. const bezieht sich>> immer auf das, was direkt links davon steht, mit einer Ausnahme: Wenn>> links nichts mehr ist, bezieht es sich auf das, was direkt rechts davon>> steht.>> Ich hätte eher gesagt, const bezieht sich in C immer auf das, was direkt> rechts daneben steht, und das ohne Ausnahme, also noch einfacher.
Das ist aber falsch.
1
// zweimal ein nichtkonstanter Zeiger auf einen konstanten int
2
intconst*p1;
3
constint*p2;
4
5
// ein nichtkonstanter Zeiger auf einen konstanten Zeiger
6
// auf einen konstanten int
7
intconst*const*p3;
> In C++ gibt es noch das const rechts neben einer Funktionsdeklaration.> Da kann diese Regel natürlich nicht gelten, aber hier hat const auch> eine ganz andere Bedeutung.
Dennoch gilt aber meine Regel auch da: const bezieht sich auf die
Funktion, also das Mehod3(...), was links davon steht.
Klar, man kann damit umgehen, aber es bleibt Murks, der sich ergab, weil
in Deklarationen abgeleitete Typen teils durch ein Symbol links vom
Namen (pointer) und teils rechts vom Namen (array, function)
gekennzeichnet werden.
Und sich folglich abgeleitete Typen ineinander schachteln, statt sich
einfach linear aufzureihen.
Weiter verkompliziert wurde es dadurch, dass Klammern darin zweierlei
verschiedene Bedeutungen haben, nämlich Funktionen und Prioritäten. Was
in C++ zur Folge hat, dass
int(a);
eigentlich gleichermassen Typumwandlung und Deklaration mit unnötiger
Klammer sein könne.
Für die natürliche Platzierung von const und volatile entsprechend der
Umgangssprache war schlussendlich kein Platz mehr, so dass die an für
Anfänger irritierende Stellen wanderten. Ausser anfangs beim strukturell
ähnlichen _far - das landete da, wo es der Anfänger vermutet aber es von
der syntaktischen Logik her nicht hingehört.
Das ist schlicht ein Konstruktionsfehler von C.
Rolf Magnus schrieb:> Das ist aber falsch.
Ich glaube eher, wie haben eine Unterschiedliche Leseweise für
Typdeklarationen.
> // zweimal ein nichtkonstanter Zeiger auf einen konstanten int> int const * p1;
Mit meiner oben vorgeschlagenen "Von-Innen-Nach-Außen-Methode" (die IMHO
auch Ritchie bei der Konzeptioen der Deklarationssystax im Kopf gehabt
hat) lese ich das so:
p1 dereferenziert ist konstant und vom Typ int.
> const int * p2;
p2 dereferenziert ist vom Typ int und dieser int-Wert ist konstant.
> // ein nichtkonstanter Zeiger auf einen konstanten Zeiger> // auf einen konstanten int> int const const p3;
p3 dereferenziert ist konstant,
nochmals dereferenziert ist er wieder konstant und vom Typ int.
Diese Leseweise mag nach holprigem Deutsch aussehen, ist aber bei der
systematischen Analyse und Synthese stark verschachtelter Deklarationen
mit durchmischten Pointern, Arrays und Funktionspointern von Vorteil.
>> In C++ gibt es noch das const rechts neben einer Funktionsdeklaration.>> Da kann diese Regel natürlich nicht gelten, aber hier hat const auch>> eine ganz andere Bedeutung.>> Dennoch gilt aber meine Regel auch da: const bezieht sich auf die> Funktion, also das Mehod3(...), was links davon steht.
Man könnte auch sagen, das const bezieht sich auf die Membervariablen,
die von der Methode nicht verändert werden. Dadurch, dass rechts vom
const nichts steht, wird angezeigt, dass die konstanten Dinge woanders
stehen, nämlich dort, wor die Membervariablen deklariert sind. Insofern
gilt meine Regel ebenfalls :)
Nur zur Erinnerung: Die Reihenfolge der Schlüsselworte vor dem "*" ist
irrelevant. Ob man
long int extern const *p;
oder
extern int const long *p;
oder
const long extern int *p;
schreibt ist schnurzpiepegal. Es landet alles im gleichen Topf.
Yalu X. schrieb:>> int const * p1;>> Mit meiner oben vorgeschlagenen "Von-Innen-Nach-Außen-Methode" (die IMHO> auch Ritchie bei der Konzeptioen der Deklarationssystax im Kopf gehabt> hat) lese ich das so:>> p1 dereferenziert ist konstant und vom Typ int.
Das ist falsch, const bezieht sich hier auf int.
>> const int * p2;>> p2 dereferenziert ist vom Typ int und dieser int-Wert ist konstant.
Das ist richtig. Bei
int const * p1;
const int * p2;
haben p1 und p2 den gleichen Typ!
Für einen konstanten Zeiger mußt du
int * const p3;
schreiben.
Manche Leute schreiben die Qualifier auch einheitlich rechts neben den
Typ, auf den sie sich beziehen.
Jürgen
Juergen schrieb:>> p1 dereferenziert ist konstant und vom Typ int.>> Das ist falsch, const bezieht sich hier auf int.
Passt schon. Er wird ja erst deferenziert und ist dann erst konstant.
Sprachlich holpert das eben etwas, man muss da geistige "sequence
points" bei der Zerlegung einfügen.
Intention von Ritche war es, die Deklaration übersichtlich zu machen,
damit der Programmierer es einfacher hat. Aber bekanntlich ist "gut
gemeint" das Gegenteil von "gut gemacht" und das heutige Ergebnis ist,
dass der Mensch wie ein Compiler denken muss, um diesen Mist überhaupt
verstehen zu können.
Wir haben es so gelernt, dass man immer von rechts nach links lesen
soll.
int const * p1;
p1 ist ein Pointer auf ein konstanter Int.
const int * p1;
p1 ist ein Pointer auf eine Int-Konstante.
int * const p1;
p1 ist ein konstanter Pointer auf ein Int.
const int * const p1;
p1 ist ein konstanter Pointer auf eine Int-Konstante.
mfg
Urban B. schrieb:> Wir haben es so gelernt, dass man immer von rechts nach links lesen> soll.
Was ist demzufolge
int (*p)[];
Nope. Von innen nach aussen ist der korrekte Weg. Wobei es bei komplexen
Type-Casts mangels Namen als Anker nicht unbedingt einfach sein muss,
das innerste "innen" überhaupt zu finden.
A. K. schrieb:> Urban B. schrieb:>> Wir haben es so gelernt, dass man immer von rechts nach links lesen>> soll.>> Was ist demzufolge> int (*p)[];
Diese Eselsbrücke ist nur für const-Sachen gedacht, also um rauszufinden
ob nun der Pointer oder die Variable selbst konstant ist (oder beides)
;-) Darum ging es ja in den letzten paar Beiträgen, deshalb habe ich
diese Eselsbrücke mal erwähnen wollen.
Juergen schrieb:> Manche Leute schreiben die Qualifier auch einheitlich rechts neben den> Typ, auf den sie sich beziehen.
Ich bin inzwischen einer davon. Und leide noch heute darunter, dass
Teile der Code-Basis noch nicht konvertiert wurden.
Richtig toll ist das nicht, aber immerhin kann man dann die "qualifier"
konsistent schreiben:
Zitat von
http://stackoverflow.com/questions/2478151/why-is-volatile-parasitic-in-c
Always write the const / volatile qualifier after what you wanted to
qualify. It is the only way to write qualifiers consistently, because
you can write both volatile int and int volatile when you want a
volatile integer, but only int * volatile will give you a volatile
pointer.
Yalu X. schrieb:> Rolf Magnus schrieb:>> Das ist aber falsch.>> Ich glaube eher, wie haben eine Unterschiedliche Leseweise für> Typdeklarationen.
Ja, du versuchst, die vermutlich ursprünglich gedachte Leseweise
anzuwenden, ich versuche, die durch was zu ersetzen, das für mich mehr
Sinn ergibt. Keine Ahnung, welche Variante nun die bessere ist. ;-)
> Mit meiner oben vorgeschlagenen "Von-Innen-Nach-Außen-Methode" (die IMHO> auch Ritchie bei der Konzeptioen der Deklarationssystax im Kopf gehabt> hat) lese ich das so:>> p1 dereferenziert ist konstant und vom Typ int.
Damit hab ich insofern schon meine Schwierigkeit, als daß für mich das *
hier in der Deklaration ausschließlich die Bedeutung "Zeiger auf das,
was davor steht" hat, während das dereferenzierungs-Sternchen damit
erstmal direkt nichts zu tun hat.
Daß die Dereferenzierung und die Zeigerdeklaration das selbe Zeichen
nutzen ist natürlich Absicht und resultiert wohl aus der von dir
angegebenen Leseweise, aber ich finde das unlogisch, weil es zwei ganz
verschiedene Dinge sind.
> Man könnte auch sagen, das const bezieht sich auf die Membervariablen,> die von der Methode nicht verändert werden.
Genauer gesagt beziehen sie sich auf den this-Pointer innerhalb der
Funktion. Dieser ist dann nämlich ein Zeiger auf const. Alle Zugriffe
auf die Membervariablen werden (entweder implizit oder explizit) über
diesen durchgeführt, also sind sie speziell in dieser Funktion auch alle
const.
> Dadurch, dass rechts vom const nichts steht, wird angezeigt, dass die> konstanten Dinge woanders stehen, nämlich dort, wor die Membervariablen> deklariert sind.
Aber dennoch bezieht sich das const nicht ganz allegemin auf die
Membervariablen, sondern nur auf Zugriffe auf diese aus der Funktion
heraus.