private bleibt wirkungslos
-
Hallo,
Ich versuche gerade mich wieder in C++ einzuarbeiten, dazu habe ich in Anlehnung an "Volkard's Kurs" gerade die Rational Klasse erstellt. Die Klasse stellt eine Bruchzahl dar und es geht um das ueberladen von Operatoren.// rational.h /* //*/ #ifndef RATIONAL #define RATIONAL class Rational { private: int m_zaehler; int m_nenner; // ... public: Rational(int zaehler, int nenner); Rational operator*(Rational rhs); // ... }; #endifDie Funktion operator* habe ich folgendermassen geschrieben:
Rational Rational::operator*(Rational rhs) { int resultZaehler = m_zaehler * rhs.m_zaehler; int resultNenner = m_nenner * rhs.m_nenner; Rational result(resultZaehler, resultNenner); return result; };Soweit sogut, in einer main() kann ich das ganze testen und es funktioniert - aber warum? rhs.m_nenner und rhs.m_zaehler duerften doch als "private" deklariert, eigentlich gar nicht zugaenglich sein, oder? Habe ich etwas bei der "private" Deklaration falsch gemacht?
-
Hi Fabeltier
solange du dich in deiner klasse befindest das du durch die beiden :: ausdrueckstRational Rational::operator*(Rational rhs)kannst du auch auf deine privat member zugreifen. Sobald du aber ausserhalb deiner Klasse versuchst darauf zuzugreifen z.b in deiner Main durch
Rational r; cout<<r.m_zaehler<<endl;wird dir der Compiler ne abfuhr erteilen und sagen, dass m_zaehler privat ist.
MFG
chewbo
-
Interessant,
Ich dachte, das "rhs" zwar vom selben Typ ist, aber dennoch als fremdes Objekt angesehen werden muesste. Der operator*() ist ja hier nur Bestandteil von soz. "lhs" und "rhs" waere somit fremd. Nja, werd damit wohl noch etwas rumspielen muessen. Danke.
-
Kam mir auch irgendwie konmisch vor, dass man scheinbar ueber ein Objekt einer Klasse auf private Elemente eines anderen Objekts dieser Klasse zugreifen kann.
Kann man die eigentlich auch noch aendern (falls man aus versehen nicht als const uebergibt)?
Irgendwie dachte ich, es sei logischer, nur das Objekt selbst und nicht Objekte der gleichen Klasse koennten auf private zugreifen. Aber dann wuerde man wohl Probleme mit de copyconstructor kriegen...
Komisch finde ich, dass das z.B auch in Bruce Eckels Thinking in C++ nicht erwaehnt wird. Oder hab ichs ueberlesen?
-
Shinja schrieb:
Kann man die eigentlich auch noch aendern (falls man aus versehen nicht als const uebergibt)?
Ja kann man. Wieso ist das komisch? Es wird doch nicht per Objekt gekapselt sondern auf Klassenebene.
grüße
-
David hat das ganz gut zusammengefasst:
Die Kapselung bezieht sich auf die Klasse, nicht auf das Objekt.
Du BRAUCHST diese Möglichkeit für Operatorüberladung, Kopierkonstruktor und Vergleichsmethoden, möglicherweise auch noch an anderen Stellen.
Das ist also durchaus beabsichtigt und kein Fehler.
-
Gut danke, der Hinweis mit der Klassenebene laesst mich da klarer durchblicken - das hatte ich vorher wohl falsch (Objektebene) verstanden. :xmas2:
-
Für protected ist der Schutz allerdings auch auf Objektebene. Du kannst nur this->protectedMember benutzen.
-
Nein, Optimizer,
auch andere Methoden der gleichen Klasse (sogar statische Methoden der Klasse) können mittels eines Objektzeigers auf protected Elemente des Objekts zugreifen (denn wenn es schon für private geht, dann für protected erst recht!).
-
Es ist zwar kein Muss, aber du solltest binäre Operatoren besser auf Namensraumebene überladen und nicht auf Klassenebene.
class Rational { //... }; Rational operator*(const Rational& lhs, const Rational& rhs) { //... }Und sofern der Zugriff auf private Member notwendig ist, muss noch eine friend Deklaration innerhalb der Klasse stehen.
class Rational { //... friend Rational operator*(const Rational& lhs, const Rational& rhs); //... };Das hat den Vorteil, dass hier Konstruktoren für _beide_ Operanden implizit herangezogen werden können, bei der Klassenimplementation ist das nur beim rechten Operand der Fall. Und normalerweise will man ja, dass sowohl 'a op b' als auch 'b op a' funktioniert.
-
Shinja schrieb:
Kam mir auch irgendwie konmisch vor, dass man scheinbar ueber ein Objekt einer Klasse auf private Elemente eines anderen Objekts dieser Klasse zugreifen kann.
Kann man die eigentlich auch noch aendern (falls man aus versehen nicht als const uebergibt)?
Irgendwie dachte ich, es sei logischer, nur das Objekt selbst und nicht Objekte der gleichen Klasse koennten auf private zugreifen. Aber dann wuerde man wohl Probleme mit de copyconstructor kriegen...
Komisch finde ich, dass das z.B auch in Bruce Eckels Thinking in C++ nicht erwaehnt wird. Oder hab ichs ueberlesen?
Wie meine Vorredner, hier noch ein Beispiel, um zu verdeutlich, wie ungünstig eine Kapselung auf Objektebene wäre:
class Foo { int foo_; public: // ... int select_foo(const Foo& other) const { const Foo& r = rand() % 2 ? *this : other; return r.foo_; } };Offensichtlich könnte eine Verletzung auf Objektebene nur während der Laufzeit festgestellt werden und auch dann müsste man prüfen, ob nicht other zufällig auf dasselbe Objekt wie *this verweist. Jedenfalls ist eine Prüfung zur Laufzeit statt beim Compilieren etwas, dass wir gerade vermeiden wollen.
-
Soweit müsste man gar nicht gehen. Private/protected Zugriff auf Objektebene würde in C++ nur Sinn machen, wenn man prüft, ob ein Member zu this gehört oder nicht. In deinem Fall gehört foo_ zu r und müsste somit einen Compilerfehler verursachen. Die Laufzeitbindung von r ist daher nicht wirklich entscheidend.
-
@ groovemaster:
Danke, das Ueberladen von Operatoren ausserhalb der Klassendeklaration kam in den weiteren Kapiteln
und soweit ich mich noch erinnern kann an frueher, war das ja auch eine der wenigen "sinnvollen" Anwendungen von friend Deklarationen (soweit bin ich mom aber noch nicht) - gut, aber damit nerv ich dann in anderen Posts. Soweit so gut - vielen Dank fuer die Erklaerungen zum Thema "private"!
-
Ich danke ebenfalls. Wahrscheinlich ist es den meisten Leuten sofort ersichtlich gewesen als Anfänger, dass private eben für alle Objekte dieser Klasse gilt (eben Klassenbezogen) Ich habe da nicht genug drüber nachgedacht und hab intuitiv private als Objektbezogen interpretiert.
Naja, habs dann ja später durch Copyconstructor und co rausgefunden. Bin aber froh, dass es mir wenigstens nicht alleine so ergangen ist.
-
Wenn da so
:const Rational operator*(const Rational& lhs, const Rational& rhs);
-
Freak_Coder schrieb:
Wenn da so
:const Rational operator*(const Rational& lhs, const Rational& rhs);Begründung?
-
Freak_Coder schrieb:
Wenn da so
:const Rational operator*(const Rational& lhs, const Rational& rhs);Durchaus möglich, mache ich meistens auch so. Ist aber keinesfalls zwingend. Genauso wenig wie die Argumente per Referenz zu übergeben. Alexandrescu hat zB mal was dazu geschrieben. Es ging hier ja lediglich um das Prinzip zwischen Klassen- und Namensraumüberladung von binären Operatoren. Die letztendliche Implementation hängt sowieso vom jeweiligen Szenario ab.
-
groovemaster schrieb:
Soweit müsste man gar nicht gehen. Private/protected Zugriff auf Objektebene würde in C++ nur Sinn machen, wenn man prüft, ob ein Member zu this gehört oder nicht. In deinem Fall gehört foo_ zu r und müsste somit einen Compilerfehler verursachen. Die Laufzeitbindung von r ist daher nicht wirklich entscheidend.
Es ist doch das selbe Objekt. r und this haben die selbe Adresse, zeigen auf den selben Speicherbereich, also sind es die selben Objekte. Es wird ja kein neues Objekt, sondern nur ein Alias für das selbe Objekt erzeugt.
-
groovemaster schrieb:
Genauso wenig wie die Argumente per Referenz zu übergeben. Alexandrescu hat zB mal was dazu geschrieben.
Warte mal. Alexandrescu bezog sich dabei auf eine Kopiersemantik. D.h. (wenn Du das gleiche meinst wie ich, wovon ich aber ausgehe) er hat keineswegs irgendwo geschrieben, dass man Argumente nicht per Referenz übergeben sollte -- außer für den Fall, dass man sie danach eh kopiert. Folgender Code ist natürlich ein wenig unsinnig:
void foo(T const& v) { T tmp = v; // Kopie // ... }Dann hätte man nämlich gleich eine Kopie übergeben können. Aber ansonsten sollte man bei non-PODs durchaus immer Referenzen verwenden.
-
@Konrad
Ja, das meinte ich. Aber mir ist nicht ganz klar, worauf du hinaus willst. Dein Beitrag steht doch in keinem Widerspruch zu meiner Aussage. Richtlinien sind nunmal nicht zwingend oder implizieren Allgemeingültigkeit.DEvent schrieb:
Es ist doch das selbe Objekt. r und this haben die selbe Adresse, zeigen auf den selben Speicherbereich, also sind es die selben Objekte. Es wird ja kein neues Objekt, sondern nur ein Alias für das selbe Objekt erzeugt.
Ich habe ja auch nicht gesagt, dass das, was camper geschrieben hat, falsch ist. Das Beispiel widerstrebt nur dem Design von C++, also dem statischen Typsystem und der daraus resultierenden statischen Fehlerbehandlung. Und auf der Basis, also wo Laufzeitbindung eine Rolle spielt, kann man eben keinen Memberzugriff auf Objektebene spezifizieren. Alles was bleibt, ist der Sichtbarkeitsbereich. Und dort spielt die Laufzeitbindung dann keine Rolle mehr.
-
camper schrieb:
Begründung?
Damit zB sowas nicht möglich ist:
Rational a,b,c; //... a*b = c;Bei einem nicht-Konstanten Rückgabewert würde dies funktionieren...
Aber ich denke mal du weißt das schon und willst mich jetzt eines besseren Belehren