[Hilfe] virtual function overwritting

netrobot

Erfahrenes Mitglied
habe ein folgendes problem: (unter VC++)
#include <iostream>
using namespace std;

class B
{
public:
f1()
{
f2();
}
private:
virtual f2()
{
cout<<"B::f2()"<<endl;
}

};

class D :public B
{
f2() //überschreibt B::f2, geht es?
{
cout<<"D::f2()"<<endl;
}
};


void main()
{
B* bp = new D;
bp->f1();
}

in class B wird die private definierte virtual funktion f2 von D:: f2()überschrieben.
aber in main wenn ich "bp->f1()"aufrufe, dann soll eigentlich B::f2() aufgerufen werden, weil die ist privat.
Die wahrheit ist D::f2 wird dadurch aufgerufen. Anscheinend D::f2 hat wirklich B::f2 überschrieben, obwohl die private elementfunktion ist.
ist es ein bug von VC?
 
Nein es ist kein Bug...
C++ ruft dynamisch zur Laufzeit automatisch die entsprechende Funktion des
entsprechenden dynamischen Typs auf, in deinem Fall bp vom
dynamischen Typ D*, wenn sie als virtual deklariert ist, das hat in deinem Fall
auch nix mit den Zugriffsrechten zu tun.
Wenn du im main f2 aufrufen würdest und diese Funktion in D als private deklariert
hättest, dann auch nur dann würde der Compiler dir meckern,
so aber nicht...

Wenn du es so beibehalten möchtest dann lass das virtual vor der Funktion weg.

Gruß

RedWing

P.S. Benutze doch das nächste mal die dir vom Forum angebotenen Code Tags,
damit es die Leser des Threads auch leichter haben deinen Code zu verstehen...
 
Zuletzt bearbeitet:
verstehe immer noch nicht. Zuerst bp ist nicht vom Typ D, es ist vom Typ B, zeigt aber auf D instanz.
zweistens, jede class hat eine vtable, die bei Instanzierung von Class erzeugt. "new D" heisst, es versucht eine instanz von class D zu erzeugen, aber muss zuerst eine instanz von B erzeugen, dann wird in der vtable ein Zeiger auf B::f1 erzeugt, aber die Adresse noch nicht festgelegt(late binding), jetzt konstructor von D wird erst aufgerufen, dadurch ist ein eigene vtable erzeugt. sagen wir D::vtable. in dieser vtable sind alle zeigér auf virtuale funktionen von B drin, falls die virtuale funktionen nicht von abgeleiteter classen überschrieben werden sollen. ausserdem noch die virtuale funktionen, die in D definiert sind, hinzufügt. d.h. in unserem Beispiel in D::vtable steht B::f1, eigentlich noch D::f2(), aber diese funktion wegen private B::f2(), darf nicht existieren. Das ergebnis zeigt aber anders. in D::table stehen B::f1(), D::f2(). WIESO?
 
um diese effect zu verhinden, definieren wir private: B::f2() const, dann bei erstellung von D::table wird den zeiger auf B::f2() nicht ersetzt vom Zeiger auf D::f2()
 
netrobot hat gesagt.:
verstehe immer noch nicht. Zuerst bp ist nicht vom Typ D, es ist vom Typ B, zeigt aber auf D instanz.
RedWing hat gesagt.:
C++ ruft dynamisch zur Laufzeit automatisch die entsprechende Funktion des
entsprechenden dynamischen Typs auf, in deinem Fall bp vom
dynamischen Typ D*,
B ist der statische Typ von bp, da er sich zur Laufzeit nicht verändern kann

aber muss zuerst eine instanz von B erzeugen,

Es wird einzig und allein eine Instanz vom Typ D erzeugt und D ist nunmal
ein B.

virtual heißt für mich das dynamisch zur Laufzeit je nachdem von welchem Typ
die Instanz ist die entsprechende Methode aufgerufen wird,
und da du nun mal f2 in B als virtual deklariert hast und in D überscheibst
wird diese ausgeführt da bp nunmal zum Zeitpunkt des Aufrufes vom Typ
D* ist...

aber diese funktion wegen private B::f2(), darf nicht existieren.
f2 ist zwar private aber du rufst f2 indirekt über f1 auf. Und die is nun mal public.
Somit umgehst du also indirekt deine gesetzten Zugriffsrechte..
Und f2 is virtuell und ruft somit D::f2 auf da ja der Aufrufer vom Typ D*
ist...

Übrigens ich bin froh das ich mich mit vtables und solchen Geschichten als
Anwender eines Compilers nicht auseinandersetzen muss und ich von daher
zum Thema vtables auch nicht viel sagen kann und auch nicht muss...

Gruß

RedWing
 
Code:
#include <iostream>
using namespace std;

class B
{
	public:
		int x ;
	virtual void setx(void)
	{
		x= 1;

	}
};

class D : public B
{
	double x ;
	void setx(void)
	{
		x = 1.1;
		
	}
};

main()
{
	B* bp = new D;
	bp->setx();

}

D ableitet von B, d.h. D hat auch ein elment heisst int x, aber D selber hat ein element double x, man kann nicht 2 gleichen variablen unterschiedliche typen zuweisen.
hier passiert es.
 
Doch man kann.
Sobald du "double x" in D deklarierst überschattest du das "int x" aus der
Basisklasse. Somit ist innerhalb von D das "double x" gültig und nicht mehr
das "int x" aus der Basisklasse..;)

Gruß

RedWing
 
Wie RedWing schon sagt, du hast nicht nur eine Variable x, sondern zwei. Wenn du ein Objekt D anlegst, besitzt dieses die Variablen: B::x und D::x
Du kannst auch beide nutzen, indem du den Scopeoperator verwendest.

z.B.
Code:
void D::setx(void)
{
  x = 1.1;  // verwendet D::x
  B::x = 5;  // verwendet B::x

}

oder:

B* bp = new D;
bp->setx();
bp->x = 5;                 // Zugriff auf integer B::x, da bp pointer auf Basisklasse
((D*)bp)->x = 3.2;      // Zugriff auf double D::x
 
Das geht natürlich auch mit Methoden

main()
{
B* bp = new D;
bp->setx(); // verwendet D::setx() da virtuell
bp->B::setx(); // verwendet B::setx() da explizit mit scope
}
 
Zurück