Sichtbarkeit bei Vererbung
-
Hallo,
ich habe eine Klasse Base:
class Base { protected: virtual void postUpdate() { } public: void update() { postUpdate(); } };und von der leite ich jetzt ab und überschreibe postUpdate. Allerdings ändere ich die Sichtbarkeit von postUpdate auf private:
class Derived : Base { private: virtual void postUpdate() { } };Zu meinem Erstaunen funktioniert das. Ich dachte man kann in Kindklassen die Sichtbarkeit nur erweitern? Also z.b. von protected auf public. Aber wieso kann ich sie hier einschränken?
-
mendelerbse schrieb:
Aber wieso kann ich sie hier einschränken?
Weil es erlaubt ist. Oder was willst du hören?
Man kannpublic,protectedoderprivatevererben.publicundprivatehaben durchaus einen Sinn, beiprotectedist es mir bisher noch nicht klar geworden.Eine
privateVeerbung kann man zum Beispiel für sowas verwenden:class AbstractObject { protected: virtual void specialise() const = 0; public: void doSomething() const; }; // Jetzt möchte ich ein ganz spezielles AbstractObject verwende, // es wird allerdings nur einmal vorkommen und sich in der Klasse // Foo befinden. Statt einer neuen Klasse zu erstellen, kann // ich eine private Vererbung machen. class Foo : private AbstractObject { private: virtual void specialise() const { // was spezielles ;) } };Eine
privateVererbung ist also grundsätzlich eine has-a Beziehung, allerdings kann man das Objekt noch spezialisieren, da man Zugriff auf denprotectedBereich hat.Grüssli
-
Du hast meine Frage nicht verstanden. Hab allerdings auch einen Fehler in meinem Code: Es muss heißen class Derived : public Base - also ne stink normale public Vererbung. Es geht mir hier um die Änderung der Sichtbarkeit einer METHODE!
-
mendelerbse schrieb:
Du hast meine Frage nicht verstanden. Hab allerdings auch einen Fehler in meinem Code: Es muss heißen class Derived : public Base - also ne stink normale public Vererbung. Es geht mir hier um die Änderung der Sichtbarkeit einer METHODE!
Achso, das ist kein Problem. Die Signatur der Funktion ist unabhängig von der Sichtbarkeit und damit die Polymorphie zieht, muss nur die Signatur gleich sein. Man kann also eine ableitende Klasse nicht dazu zwingen, die virtuellen Funktionen in irgendeiner Sichtbarkeit zu halten. Jede Klasse bestimmt dies ganz alleine.
Grüssli
-
Mh, so ganz versteh ich das noch nicht. Ich kann doch zb nicht einfach eine public virtual methode in Base in der Derived Klasse zu einer proteced oder gar private methode machen? Das würde doch dieses Liskow Substitute Principle Ding (oder wie das heißt) verletzen. Sprich das hier:
class Base { public: virtual void foo() { } }; class Derived : public Base { proteced: virtual void foo() { } }; Base* b = new Derived(); b->foo(); // Aufruf geht nicht mehr (?), obwohl Base sagt, dass foo public ist
-
mendelerbse schrieb:
Mh, so ganz versteh ich das noch nicht. Ich kann doch zb nicht einfach eine public virtual methode in Base in der Derived Klasse zu einer proteced oder gar private methode machen? Das würde doch dieses Liskow Substitute Principle Ding (oder wie das heißt) verletzen. Sprich das hier:
class Base { public: virtual void foo() { } }; class Derived : public Base { proteced: virtual void foo() { } }; Base* b = new Derived(); b->foo(); // Aufruf geht nicht mehr (?), obwohl Base sagt, dass foo public istDer Aufruf funktioniert sehr wohl. Die Erreichbarkeit von Membern hängt nur vom statischen Typ des Objektes ab und wird folglich nur beim Compilieren überprüft.
Derived d; d.foo(); // fehler Base& b = d; b.foo(); // okLSP ist also nicht verletzt, was allerdings auch nicht der entscheidende Maßstab ist. Denn natürlich kann die Sprache dich nicht daran hindern, eine Funktion so zu überschreiben, dass ihr Verhalten nicht mehr zu dem der Basisklasse passt. Es drängt sich kein Grund auf, der die Veränderung der Erreichbarkeit von Membern in beliebiger Weise verbieten müsste.
-
camper schrieb:
Es drängt sich kein Grund auf, der die Veränderung der Erreichbarkeit von Membern in beliebiger Weise verbieten müsste.
Finde ich schon. Wenn ich public ableite, dann sagte ich, dass Derived ein Base IST. Ist doch dann bescheuert, wenn ich aber bestimmte Methoden von Base nicht mehr aufrufen kann. Dadurch ist Derived ja kein Base mehr. Leuchtet mir absolut nicht ein, wieso nicht nur eine Erweiterung der Sichtbarkeit (also von protected auf public etc) erlaubt ist, sondern auch eine Einschränkung.
-
mendelerbse schrieb:
Leuchtet mir absolut nicht ein, wieso nicht nur eine Erweiterung der Sichtbarkeit (also von protected auf public etc) erlaubt ist, sondern auch eine Einschränkung.
Ich denke dein Fehler ist, dass du denkst, dass es die gleiche Funktion einfach überschreibt, was aber nicht der Fall ist. Es wird eine neue Funktion angelegt, welche die alte Funktion überdeckt. Das
virtualbindet sie einfach in der vtable noch zusammen. Aber grundsätzlich ist es eine eigenständige Funktion. Soviel zum technischen Aspekt.
Man sollte hier aber natürlich ein wenig vorsichtig sein, da man schnell Verwirrung stiften kann. Aber C++ schreibt halt kein Programmierstil oder sowas vor, sondern erlaubt meistens sehr vieles, was man auch für absolute Verwirrung missbrauchen kann. Bei C++ liegt es halt in der Verantwortung des Programmierers.Grüssli
PS: WOW! Ein camper! *Fotoapparat auspackt*
