virtuelle Methoden
-
Hallo,
bei virtuellen Methoden gibt es ja folgende Möglichkeiten:
1: virtual void foo() = 0; 2: virtual void foo() { ... } 3: virtual void foo() = 0 { ... } 4: virtual void foo();Könntet ihr mir sagen ob folgende Aussagen stimmen:
Bei 1) MUSS die Subklasse überschreiben (sonst ist sie selber abstrakt)Bei 2) KANN die Subklasse überschreiben. Die Subklasse kann hier Funktionalität der Basisklasse nutzen
Bei 3) MUSS die Subklasse überschreiben UND kann Funktionalität der Basisklasse nutzen.
Geht 4) überhaupt? Ich seh da keinen Sinn drinnen, eine Methode als virtuell zu deklarieren aber sie nicht zu definieren. Geht das?
-
ChampionsLeagueFinale schrieb:
Geht 4) überhaupt?
Ja. Es passiert das Selbe, wie bei jeder anderen undefinierten Funktion.
-
Version 2 und 4 sind technisch gesehen das selbe, nur daß bei der letzten Variante noch eine Definition der (eigenen) Methode dazukommen muß.
(btw, ich wußte bisher nicht, daß Version 3 vom Standard abgesegnet ist)
-
CStoll schrieb:
Version 2 und 4 sind technisch gesehen das selbe, nur daß bei der letzten Variante noch eine Definition der (eigenen) Methode dazukommen muß.
(btw, ich wußte bisher nicht, daß Version 3 vom Standard abgesegnet ist)
Ist auch nicht, weder im Aktuellen noch im Kommenden.
-
edit: Frage hat sich geklärt.
Zusammengefasste Erkenntnis:
- Funktionen dürfen nicht gleichzeitig pur virtuell deklariert UND definiert werden. (zweite Note zu §10.4,2) D.h.struct B { virtual void foo() = 0 {} //Verboten! };- Pur virtuelle Funktionen dürfen aber durchaus an anderer Stelle eine Definition haben. Bei Destruktoren ist das sogar zwingend notwendig. Folgende Möglichkeiten ergeben sich dafür:
Möglichkeit 1:
//b.h struct B { virtual ~B() = 0; }; //b.cpp B::~B() {/* ... */}Möglichkeit 2:
//b.h struct B { virtual ~B() = 0; }; inline B::~B() {/* ... */}
-
camper schrieb:
CStoll schrieb:
Version 2 und 4 sind technisch gesehen das selbe, nur daß bei der letzten Variante noch eine Definition der (eigenen) Methode dazukommen muß.
(btw, ich wußte bisher nicht, daß Version 3 vom Standard abgesegnet ist)
Ist auch nicht, weder im Aktuellen noch im Kommenden.
Aber so sollte es gehen:
class foo { virtual void bar() = 0; }; foo::bar() { // tue etwas } class derived_foo : foo { virtual void bar() { foo::bar(); } };
-
Aus dem C++-Standard:
10.4 Abstract classes §2 schrieb:
A pure virtual function need be defined only if explicitly called with the qualified-id syntax (5.1). [Example:
class point { /* ... */ }; class shape { // abstract class point center; // ... public: point where() { return center; } void move(point p) { center=p; draw(); } virtual void rotate(int) = 0; // pure virtual virtual void draw() = 0; // pure virtual // ... };—end example] [Note: a function declaration cannot provide both a pure-specifier and a definition
—end note] [Example:struct C { virtual void f() = 0 { }; // ill-formed };
-
Dh eine Methode kann pure virtual sein und dennoch eine Definition haben (nur halt nicht im Header?)
Macht man das, wenn man in der Basisklasse Funktionalitaet zur Verfuegung stellen will aber dennoch alle Subklassen die Methode ueberschreiben sollen?
-
fragger2 schrieb:
Dh eine Methode kann pure virtual sein und dennoch eine Definition haben (nur halt nicht in der Klassendefinition?)
Habs mal korrigiert - im Header gehts, wenns explizit inline deklariert wird und außerhalb der Klassendefinition geschieht.
Macht man das, wenn man in der Basisklasse Funktionalitaet zur Verfuegung stellen will aber dennoch alle Subklassen die Methode ueberschreiben sollen?
Jup. Spezialfall sind Destruktoren, da MUSS die Funktionalität zur Verfügung gestellt werden, weil alle Destruktoren von abgeleiteten Klassen den Dtor implizit qualifiziert aufrufen. Dahingehend finde ich die von Nexus zitierte Zeile im Standard etwas missverständlich.
class M; struct B { ~B() = 0; }; //Pflicht: B::~B() {} struct D : public B { M m; //ggf nur implizit vom Compiler generiert: D(); ~D(); }; D::D() //ggf implizit generierte Initialisierungsliste: : B(), m() {} D::~D() {} //Psuedocode, das wird auf jeden Fall implizit generiert: /*: m.~M(), B::~B()*/ //->qualifizierter Dtor-Aufruf des pur virtuellen Dtors!
-
Dh eine Methode kann pure virtual sein und dennoch eine Definition haben (nur halt nicht im Header?)
IMHO ist das nicht vom Standard abgesegnet => Es kann gehen, muss aber nicht. Hier haben die compiler halt "Freiheiten".
Macht man das, wenn man in der Basisklasse Funktionalitaet zur Verfuegung stellen will aber dennoch alle Subklassen die Methode ueberschreiben sollen?
Was erreicht man damit:
Zumindest bei mir (VS 2005) erkennt er ueber den Header, das die Funktion abstrakt ist, d.h. die Klasse verhaelt sich nach aussen "normal", man kann sich also auf den Header verlassen.
Die Implementation der Funktion wird mit zugelinkt aber wird ueber normale Funktionsaufrufe natuerlich nicht angesprungen. Das einzigste wie man den Code zum ausfuehren bekaeme ist ueber volle Qualifikation aka KlasseName::MethodenName, also so wie wenn man das "virtual" grundsätzlich austricksen woellte.Ergo -> Tut man eigentlich ueberhaupt nicht.
Man erreicht ähnliche Effekte ueber andere, sauberere, offensichtlichere und damit besser wartbare Sprachmittel.
Sowas nutzt man also eher, um den Nachfolger, der seinen Code warten soll, das Leben zur Hölle zu machen, warum auch immer ^^
Anmerkung: Oft genug ist man selber sein eigener Nachfolger, man muss nur oft genug Dinge "vergessen"
+Ciao ...
-
RHBaum schrieb:
Dh eine Methode kann pure virtual sein und dennoch eine Definition haben (nur halt nicht im Header?)
IMHO ist das nicht vom Standard abgesegnet => Es kann gehen, muss aber nicht. Hier haben die compiler halt "Freiheiten".
Siehe Zitat von Nexus oben. pv + getrennte Definition ist nicht nur Okay, sondern ggf. auch durchaus notwendig. pv+Definition gleichzeitig ist laut Standard ill-formed. Natürlich dürfen auch hier compilerspezifische Extensions greifen, die das eigentlich ungültige C++ dann anstandslos und korrekt übersetzen. Ist dann eben nur nicht portabel.
[...] Das einzigste wie man den Code zum ausfuehren bekaeme ist ueber volle Qualifikation aka KlasseName::MethodenName, also so wie wenn man das "virtual" grundsätzlich austricksen woellte.
Ergo -> Tut man eigentlich ueberhaupt nicht.
Wenns nicht grade um Destruktoren geht, wo es Pflicht ist.
Man erreicht ähnliche Effekte ueber andere, sauberere, offensichtlichere und damit besser wartbare Sprachmittel.
Für nicht-Dtoren richtig. Wenn man eine Implementierung bereitstellt, muss man die auch irgendwo dokumentieren, damit der Anwender, der foo() in der abgeleiteten Klasse implementiert, das auch weiß. Wenn man stattdessen eine protected Funktion
void defaultFooBehavior();in der Klasse deklariert, weiß jeder, was Sache ist.