Frage zu unzulaessigen Referenzzuweisungen



  • Hi,

    ich habe gerade folgenden Beispielcode (nachdem ich urspruenglich einem kleinen Fehler gesucht hatte) geschrieben:

    #include <iostream>
    
    using namespace std;
    
    class Base{
    	public:
    	virtual void im() = 0;
    	virtual void imdata() = 0;
    };
    
    class A : public Base{
    	public:
    	A() : c('a'){}
    	void im(){
    		cout << "A" << endl;
    	}
    	void imdata(){
    		cout << c << endl;
    	}
    	private:
    	char c;
    };
    
    class B : public Base{
    	public:
    	B() : c('b'){}
    	void im(){
    		cout << "B" << endl;
    	}
    	void imdata(){
    		cout << c << endl;
    	}
    	private:
    	char c;
    };
    
    int main(int argc, char **argv){
    	A a;
    	B b;
    	Base & ref = a;
    
    	a.im();
    	b.im();
    	ref.im();
    	a.imdata();
    	b.imdata();
    	ref.imdata();
    
    	ref = b; //fehlerhafte Zuweisung, wirkungslos?
    
    	a.im();
    	b.im();
    	ref.im();
    	a.imdata();
    	b.imdata();
    	ref.imdata();
    
    	int i = 2;
    	int j = 3;
    	int & k = i;
    
    	cout << i << " " << j << " " << k << endl;
    	k = j;
    	cout << i << " " << j << " " << k << endl;
    
    	return 0;
    }
    

    Er gibt folgendes aus:

    A
    B
    A
    a
    b
    a
    A
    B
    A
    a
    b
    a
    2 3 2
    3 3 3
    

    Was passiert hier? Bei meinem urspruenglichen Problem, hatte ich auf aehnliche Art (wenn auch mit wesentlich mehr Indirektion) ein Objekt ueberschrieben.
    Hier haette ich nach der zweiten Zuweisung auf ref die Ausgabe BBBbbb erwartet.
    Warum passiert dies nicht? Und warum ist nicht vorgesehen, solche potentiell unzulaessigen Zuweisungen nur mit casts zu erlauben. Immerhin kann hier ein Objekt eines anderen Subtypen ueberschrieben werden.
    Die Integer Referenz, arbeitet, wie ich es mir gedacht haette.

    Vielen Dank fuer eure Hilfe.


  • Mod

    topfplanze schrieb:

    Immerhin kann hier ein Objekt eines anderen Subtypen ueberschrieben werden.

    Das ist nicht was passiert. Alles was passiert, ist, dass der Basisklassenanteil des a-Objektes mit dem Inhalt des Basisklassenanteils des b-Objektes überschrieben wird. Da die Basisklasse gar keine Daten enthält, passiert effektiv gar nichts. Der dynamische Typ des Objektes, auf das ref verweist, ändert sich schon gar nicht.
    Das ist auch nicht der tpische Slicing-Fall in dem ein Baisklassenobjekt neu erzeugt wird. Es wäre möglich, diese Zuweisung zu vermeiden, indem der Zuweisungsoperator wenigstens protected deklariert wird, praktisch sehe ich aber kein Problem. Sinnvoller Umgang mit polymorphen Basisklassen involviert für gewöhnlich Zeiger oder Referenzen derart, dass Operator i.d.R. nicht direkt angewendete werden können, eine solche Zuweisung wird also selten zufällig entstehen.



  • Danke, das hat mein Verstaendnis ueber Referenzen ein wenig verbessert, auch wenn ich das so nicht erwartet haette, dass nur der statische Typ ueberschrieben wird.
    Falls das hier noch mal jemand liest:
    Ich habe den Testcode wie folgt angepasst.

    #include <iostream>
    
    using namespace std;
    
    class Base{
    	public:
    	Base(){
    		static int ctorcount = 0;
    		baseInt = ctorcount++;
    	}
    	virtual void im() = 0;
    	virtual void imdata() = 0;
    	void imdataBase(){
    		cout << baseInt << endl;
    	}
    	private:
    	int baseInt;
    };
    
    class A : public Base{
    	public:
    	A() : c('a'){}
    	void im(){
    		cout << "A" << endl;
    	}
    	void imdata(){
    		cout << c << endl;
    	}
    	private:
    	char c;
    };
    
    class B : public Base{
    	public:
    	B() : c('b'){}
    	void im(){
    		cout << "B" << endl;
    	}
    	void imdata(){
    		cout << c << endl;
    	}
    	private:
    	char c;
    };
    
    int main(int argc, char **argv){
    	A a;
    	B b;
    	Base & ref = a;
    
    	a.im();
    	b.im();
    	ref.im();
    	a.imdata();
    	b.imdata();
    	ref.imdata();
    	a.imdataBase();
    	b.imdataBase();
    	ref.imdataBase();
    
    	ref = b;
    
    	a.im();
    	b.im();
    	ref.im();
    	a.imdata();
    	b.imdata();
    	ref.imdata();
    	a.imdataBase();
    	b.imdataBase();
    	ref.imdataBase();
    
    	int i = 2;
    	int j = 3;
    	int & k = i;
    
    	cout << i << " " << j << " " << k << endl;
    	k = j;
    	cout << i << " " << j << " " << k << endl;
    
    	return 0;
    }
    

    Die Ausgabe aendert sich dann wie erwartet auf:

    A
    B
    A
    a
    b
    a
    0
    1
    0
    A
    B
    A
    a
    b
    a
    1
    1
    1
    2 3 2
    3 3 3
    

    DAnke fuer die Erklaerung.


Anmelden zum Antworten