Frage zu protected const member
-
Hallo zusammen,
ich habe eine Klasse mit einem const member:
class Foo { public: Foo(const A& a) : _a(a){}; virtual Foo(){}; protected: const A& _a; }Die davon erbende Klasse soll allerdings auch auf
nicht const Methoden zugreifen können.class Bar : public Foo { public: Bar(A& a):Foo(a){}; virtual Bar(){}; }So habe ich natürlich nur const Zugriff.
Brauch ich da nen const_cast oder gibts ne andere Möglichkeit?
(mal abegesehen von ner zweiten Referenz)Oder würdet ihr da Vererbung nutzen?
Etwa so:class BaseMember{ const A& getMember() const = 0; } class ReadableBaseMember : public BaseMember{ public: ReadableBaseMember(const A& a):_a(a){}; const A& getMember() const{return a}; protected: const A& _a; } class WritableBaseMember : public BaseMember{ public: WritableBaseMember(A& a):_a(a){}; const A& getMember() const{return a}; A& getMember() {return a}; protected: A& _a; } class Base : public virtual BaseMember { // Alle Aufrufe über getMember(); } class Foo : public Base, public ReadableBaseMember { public: Foo(const A a&) : Base(), ReadableBaseMember(a); } class Bar : public Base, public WritableBaseMember { public: Bar(A a&) : Base(), WritableBaseMember(a){}; // und andere Methoden }Ich hoffe ihr versteht, was ich meine und ich hab keine
Fehler drin ^^Gruß,
CSpille
-
CSpille schrieb:
Ich hoffe ihr versteht, was ich meine und ich hab keine
Fehler drin ^^Hi, ohne Codetags verstehe ich garnichts

-
CSpille schrieb:
ich habe eine Klasse mit einem const member:
class Foo { public: Foo(const A& a) : _a(a){}; virtual Foo(){}; protected: const A& _a; }Die davon erbende Klasse soll allerdings auch auf
nicht const Methoden zugreifen können.class Bar : public Foo { public: Bar(A& a):Foo(a){}; virtual Bar(){}; }

Du hast eine Klasse mit einem const Member und die davon erbende Klasse soll auch auf nicht const-Methoden zugreifen können, wo ist der Zusammenhang ???
Edit: Was hast du eigentlich genau vor, was beabsichtigst du zu modellieren ?
-
Die Foo-Member-Objekte sollen getter-Methoden enthalten:
Bla* getBla() const; Blub* getBlub() const;Zusätzlich kann ein Bar-Objekt aber auch (in zusätzlichen Methoden) die Setter
verwenden:void setBla(Bla*); void setBlub(Blub*);Folglich reicht Foo ein const Objekt aus und
Bar nicht.btw: Die fehlenden Code-Tags hab ich vor dir entdeckt

-
Also, ich habe das jetzt so verstanden.
Du hast eine Basisklasse die einen Member hat. Du willst das diese Basisklasse einmal nur lesbar und einmal nur schreibar ist oder beides jenachdem was du genau willst.
class Var { }; class Base { protected: Base() { } Var var; }; class BaseWriter : virtual public Base { public: virtual void setVar(Var v) = 0; }; class BaseReader : virtual public Base { public: virtual Var getVar() const = 0; };Man kan nur ein Base bekommen, wenn man davon ableitet. Somit könnte niemand von außen außer abgeleitete Klassen auf var zugreifen.
Dann hast du einmal deinen Reader und Writer. Klassen die jetzt irgendwas damit machen sollen, erben dann entsprechend von einen der beiden oder beiden ...
-
Hallo KasF,
erstmal danke für deine Antwort!
Ich denke weißt nicht, was ich meine ^^
Es gaht darum, dass mein Objekt eine Referenz
auf ein Objekt besitz (im Konstruktor übergeben),
auf das es keinen Schreibzugriff braucht (const).
Die abgeleitete brauch allerdings den Schreibzugriff.
Als Beispiel:
Ich hab ne Tabellenzelle, der ich einen Inhalt übergebe.
Zur Widergabe des Inhaltsbrauche brauche ich keinen
Schreibzugriff.
Jetzt leite ich von Tabellenzelle ab um ne EditableTableCell
zu machen. Die kann alles, was die ursprüngliche auch kann.
Zusätzlich kann ich dann aber auch noch "verändernde" (nicht const)
Methoden aufrufen. Jetzt war für die ursprüngliche Tabellenzelle
ja nur nen const TableCell& verlangt und folglich nur ein
const TableCell& verfügbar. Was ich natürlich machen kann,
ist ihm einfach per const_cast zu sagen, dass er es darf.
(Aber ist das sauber?)Was man sonst machen kann (Der untere Code):
Ich mach die Funktionalität in eine virtuelle Basisklasse bauen.
Der member kommt dann erst in Foo (die Zelle) bzw. Bar (die editierbare)
Zelle.Ich kann die ReadableBaseMember und WritableBaseMember natürlich auch
direkt in Foo bzw. Bar implementieren ^^Gruß,
CSpille
-
CSpille schrieb:
Es gaht darum, dass mein Objekt eine Referenz
auf ein Objekt besitz (im Konstruktor übergeben),
auf das es keinen Schreibzugriff braucht (const).Brauchen ist nicht gleich dürfen

Wenn du verhindern willst, das irgendeine Memberfunktion deine Membervariable verändert, dann macht man diese Variable const. Nicht weil man keine Funktion hat die darauf schreibt ... ( Kann alles falsch sein, so aber meine Theorie
)Zu deinem Problem:
CSpille schrieb:
Es gaht darum, dass mein Objekt eine Referenz
auf ein Objekt besitz (im Konstruktor übergeben),
auf das es keinen Schreibzugriff braucht (const).->
//Niemand braucht Schreibzugriff hier drauf, "niemand" kann an var was ändern class Base { protected: Base(Var &v):var(v) { } Var &var; };Nun willst du doch ein Interface um var nur lesend anzusprechen:
//Klassen die das Privileg haben wollen in var zu schreiben, müssen hiervon erben class BaseWriter : virtual public Base { public: BaseWriter(Var &v) : Base(v) { } virtual void setVar(Var v) = 0; };Damit auch alles schön ist, stellst du ein Interface für nur Schreibzugriffe:
//Klassen die das Privileg haben wollen var zu lesen, müssen hiervon erben class BaseReader : virtual public Base { public: BaseReader(Var &v) : Base(v) { } virtual Var getVar() const = 0; };Willst du nun eine Klasse haben, die beides Unterstützt dann:
class BaseIO : public BaseWriter, public BaseReader { public: BaseIO(Var &v):BaseWriter(v),BaseReader(v) { } virtual void setVar(Var v) { var = v; } virtual const Var& getVar() const { return var; } };...
-
KasF schrieb:
class BaseIO : public BaseWriter, public BaseReader { public: BaseIO(Var &v):BaseWriter(v),BaseReader(v) { } virtual void setVar(Var v) { var = v; } virtual const Var& getVar() const { return var; } };Jetzt kriege ich aber die Krise, wieso funktioniert das nicht ?
Er verlangt nach einem Base(), aber nirgendwo wird er doch aufgerufen ...|------------BaseIO(v)-------------------| | | | |--BaseWr(v)--| |--BaseRe(v)--| | | | | | | | | | |-----------Base(v)-------| | | | | | | | | | | |-------------------------| | | | |-------------| |-------------| | | | |----------------------------------------|
-
Ist es denn notwändig die "const" Version der Klasse mit einer "const Foo&" anlegen zu können?
Wenn nein kannst du das alles einfach weglassen.
Wenn ja kannst du es z.B. so machen:class Foo { ... }; class ConstBar { public: ConstBar(Foo const& foo) : m_foo(foo) {} int GetA() const { return m_foo.GetA(); } protected: Foo const& m_foo; }; class Bar : public ConstBar { public: Bar(Foo& foo) : ConstBar(foo) {} void SetA(int a) { GetFoo().SetA(); } protected: Foo& GetFoo() { return const_cast<Foo&>(m_foo); } };Der const_cast in "Bar" ist "sicher" und erlaubt, da das Objekt auf welches m_foo (in einem Bar!) zeigt niemals wirklich const sein kann, sonst hätte es der ctor Bar::Bar nicht gefressen. Ok, das Objekt könnte doch const sein, aber dann müsste jmd. ausserhalb von Bar selbst einen const_cast geschrieben haben um es wegzucasten, und dann ist DER schuld der diesen anderen const_cast geschrieben hat

Eine 2. Referenz zu verwenden ist aber sicher die sauberere Lösung, auch wenn es ein paar Byte mehr braucht.
Und bevor du einer Klasse einen vtable verpasse die keinen braucht kannst du gleich einen 2. Referenz verwenden, da diese auch nicht mehr Speicher braucht. Und du sparst die die etwas teureren und i.A. nicht-inline-baren virtual Calls.
Ich habe sowas allerdings noch NIE gebraucht. Ich will nicht behaupten dass man es nie brauchen kann, aber wie gesagt: ist mir noch nie untergekommen.
----
virtual public Base-> der ctor der "most derived class" (in dem Fall BaseIO::BaseIO) muss alle virtual base classes konstruieren.
C++ verlangt das.BaseIO(Var &v):BaseWriter(v),BaseReader(v) { } // -> BaseIO(Var &v):Base(v), BaseWriter(v),BaseReader(v) { }Frag mich bloss nicht wieso das so ist, dazu müsste ich anfangen zu denken, und das mag ich jetzt nicht

-
hustbaer schrieb:
virtual public Base-> der ctor der "most derived class" (in dem Fall BaseIO::BaseIO) muss alle virtual base classes konstruieren.
C++ verlangt das.BaseIO(Var &v):BaseWriter(v),BaseReader(v) { } // -> BaseIO(Var &v):Base(v), BaseWriter(v),BaseReader(v) { }Frag mich bloss nicht wieso das so ist, dazu müsste ich anfangen zu denken, und das mag ich jetzt nicht

Durch die 'virtual' Ableitung hast du nur eine Version von Base in deiner BaseIO-Klasse, die aber auf zwei Wegen erreicht werden kann. Also wären auf regulärem Weg auch zwei Ctor-Aufrufe dort fällig (einmal von BaseWriter und einmal von BaseReader) - und damit eine Mehrdeutigkeit, welcher nun tatsächlich ausgeführt werden soll. Um diese Mehrdeutigkeit aufzulösen, wird die Verantwortung der untersten Kindklasse übertragen.
-
CStoll schrieb:
hustbaer schrieb:
virtual public Base-> der ctor der "most derived class" (in dem Fall BaseIO::BaseIO) muss alle virtual base classes konstruieren.
C++ verlangt das.BaseIO(Var &v):BaseWriter(v),BaseReader(v) { } // -> BaseIO(Var &v):Base(v), BaseWriter(v),BaseReader(v) { }Frag mich bloss nicht wieso das so ist, dazu müsste ich anfangen zu denken, und das mag ich jetzt nicht

Durch die 'virtual' Ableitung hast du nur eine Version von Base in deiner BaseIO-Klasse, die aber auf zwei Wegen erreicht werden kann. Also wären auf regulärem Weg auch zwei Ctor-Aufrufe dort fällig (einmal von BaseWriter und einmal von BaseReader) - und damit eine Mehrdeutigkeit, welcher nun tatsächlich ausgeführt werden soll. Um diese Mehrdeutigkeit aufzulösen, wird die Verantwortung der untersten Kindklasse übertragen.
Ahh, danke für die Antwort. Fand das auch schon irgendwie seltsam, dass ich zweimal etwas an Base durchreiche.
