Undefined Reference auf eine abstrakte Funktion?
-
Richtig, drakons Version von PolymArray::operator= weist einen anderen Parameter auf als in Array::operator=. Nur beim Rückgabetyp greift das Prinzip der Kovarianz, auf das drakon wahrscheinlich hinauswollte. Wenn ich seine Version von PolymArray::operator= einsetze, wird Array::operator= also nicht redefiniert, was der Compiler auch bestätigt:
||=== Testprogramm, Debug ===|
In functionint main()': error: cannot declare variable \a' to be of type `PolymArray'
error: because the following virtual functions are abstract:
error: virtual Array& Array::operator=(const Array&)
error: cannot declare variable `b' to be of type `PolymArray'
error: since type `PolymArray' has abstract virtual functionsGibt es noch weitere Ideen?
-
Ja, die Basisklasse muss den
operator=ebenfalls implementieren. Der Aufruf vonoperatorruft alleoperator=-Funktionen seiner Elternklassen auf. Dabei ist es ganz gleich, ob dies abstrakte Klassen sind, und dieoperator=-Funktion rein virtuell ist.
Das ist analog zur nicht virtuellenoperator=-Funktion.//so (diese Variante ist zu bevorzugen): class Array { public: virtual Array& operator = ( const Array& a ) = 0 { return *this; } virtual bool operator ==( const Array& a ) = 0; }; //oder so: class Array { public: virtual Array& operator = ( const Array& a ){ return *this; } virtual bool operator ==( const Array& a ) = 0; };
-
Tachyon schrieb:
Der Aufruf von
operatorruft alleoperator=-Funktionen seiner Elternklassen auf.Nur wenn er automatisch generiert wird. Bei selbstgeschriebenen op= muss man das falls benötigt selber machen.
Ich persöhnlich frage mich allerdings was ein polymorpher op= bewerkstelligen soll. Folgendes wäre z.B. sinnfrei:
class Fahrzeug; class Auto : public Fahrzeug {/*...*/} class Zweirad : public Fahrzeug {/*...*/} //... karre = mopped; //????
-
pumuckl schrieb:
Tachyon schrieb:
Der Aufruf von
operatorruft alleoperator=-Funktionen seiner Elternklassen auf.Nur wenn er automatisch generiert wird. Bei selbstgeschriebenen op= muss man das falls benötigt selber machen.
Jap. Für
PolymArraywird auch automatisch ein Default-operator=()generiert. NämlichPolymArray & operator=(PolymArray const &). Und dieser versucht, denoperator=vonArrayaufzurufen, was folgerichtig zu einer undefinierten Referenz führt.
Erzwingt man die Benutzung des korrekten Operatos mita = static_cast<Array&>(b), dann funktioniert es wie erwartet.
Das gleiche hast Du auch beim nicht-virtuellenoperator=:#include <iostream> struct test { test& operator=(char c){ std::cout << "char\n"; return *this; } }; int main() { test a; test b; a = 'c'; //ruft test& operator=(char c) auf b = a; //ruft default operator=() auf }PS: Du hast aber damit recht, dass der rein virtuelle Zuweiser wenig Sinn macht. In den seltensten Fällen tut er das, was man will.
-
Tachyon schrieb:
PS: Du hast aber damit recht, dass der rein virtuelle Zuweiser wenig Sinn macht. In den seltensten Fällen tut er das, was man will.
Das gilt aber auch für
operator==.Wenn man wirklich Objekte unterschiedlichen Typs vergleichen möchte (was ich an sich schon fragwürdig finde), wäre vielleicht etwas über
dynamic_castmöglich. Damit mindestensfalsezurückgegeben werden kann, wenn die dynamischen Typen unterschiedlich sind.Das Problem bei virtuellen Funktionen ist auch die Asymmetrie;
a == bkann unter Umständen etwas anderes bewirken alsb == a.
-
Danke, euer Tipp war goldrichtig! Der standardmäßig zur Verfügung gestellte Zuweisungsoperator von PolymArray bedurfte des alten, allerdings abstrakten Zuweisungsoperators.
Was ich mit einem abstrakten Zuweisungsoperator mache, kann ich euch gern sagen: Es handelt sich um eine abstrakte Basisklasse, die ihrerseits noch keine Elementdaten besitzt. Eine abstrakte Zuweisung ist da denkbar... zumindest jedoch nicht unsinnig.
-
koril-k schrieb:
Was ich mit einem abstrakten Zuweisungsoperator mache, kann ich euch gern sagen: Es handelt sich um eine abstrakte Basisklasse, die ihrerseits noch keine Elementdaten besitzt. Eine abstrakte Zuweisung ist da denkbar... zumindest jedoch nicht unsinnig.
Kannst Du mal ein Beispiel nennen, wieso das sinnvoll sein soll?
-
Tachyon schrieb:
Kannst Du mal ein Beispiel nennen, wieso das sinnvoll sein soll?
damit kann ich endlich typen ändern. schau:
Sparkonto k1; Girokonto k2; k2=k1;//wird automagisch zum Sparkonto
-
volkard schrieb:
Tachyon schrieb:
Kannst Du mal ein Beispiel nennen, wieso das sinnvoll sein soll?
damit kann ich endlich typen ändern. schau:
Sparkonto k1; Girokonto k2; k2=k1;//wird automagisch zum Sparkonto
-
volkard schrieb:
schau:
Nettes Beispiel.

-
Meine Anwendung gebe ich euch gern. Ich habe eine abstrakte Basisklasse namens "Array", jedoch ist die interne Darstellung de rDaten in den unterschiedlichen benötigten Arrays sehr verschieden. Konkret habe ich zwei Arrays: PolymArray speichert die Daten mittels Zeiger damit ich Polymorphie nutzen kann und DirecTArray speichert die Daten direkt ab wie in int a[10]. Wenn ich eine Referenz auf ein Array habe, z.B. Array& a = b wobei b z.B. ein PolymArray ist, dann soll sowohl a = b als auch a = c funktionieren, wobei c ein DirectArray ist, oder noch konkreter: a = x wobei x entweder DirectArray, PolymArray oder Referenz vom Typ Array ist. Die Zuweisung übernimmt die Daten des angegebenen Arrays und legt sie in der eigenen Datenstruktur ab. Das gelingt dem Operator deshalb, weil alle Arrays über einen gemeinsamen Datenzugriff verfügen, der in der abstrakten Klasse verlangt wird und die Darstellung der Daten nach außen hin verbirgt; nämlich Array::operator[].