[solved] dynam. Bindung kaputt???



  • hi,

    ich steh scheinbar grad vollends auf der leitung. wieso funktioniert in diesem fall die dynamische bindung nicht?

    #include <iostream>
    
    class Base
    {
    public:
    	Base()				{	this->Init();	}
    	virtual ~Base()		{}
    
    	virtual void Init() = 0;
    };
    
    void Base::Init()
    {
    	std::cout << "init base" << std::endl;
    }
    
    class Derived : public Base
    {
    public:
    	Derived()	{}
    	~Derived()	{}
    
    	void Init();
    };
    
    void Derived::Init()
    {
    	std::cout << "init derived" << std::endl;
    }
    
    int main( const int argc, const char** args )
    {
    	Derived *derived = new Derived();
    
    	return 0;
    }
    

    ausgabe:

    init base

    wth??
    was mich auch stark verstört ist, dass ich die als abstrakt gekennzeichnete methode der basisklasse definieren kann - und sogar MUSS da ich sonst 'nen linker error bekomme.

    plötzlich funktionieren die einfachsten mechanismen nicht mehr? was ist da los??

    *edit*
    ms vs2005 sp1 btw...



  • Müsste das nicht heissen tun:

    Derived *derived = new Derived;

    😕



  • komplett wurscht, leere parameterliste. und ja, a speicherleck hab i auch ;p

    *edith*

    poah, is das krank, auf was ma alles aufpassen soll. für all jene, die's wie ich auch nicht wussten:

    http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr142.htm

    You can call member functions from a constructor or destructor of an abstract class. However, the results of calling (directly or indirectly) a pure virtual function from its constructor are undefined. The following example demonstrates this:

    struct A {
      A() {
        direct();
        indirect();
      }
      virtual void direct() = 0;
      virtual void indirect() { direct(); }
    };
    

    The default constructor of A calls the pure virtual function direct() both directly and indirectly (through indirect()).

    The compiler issues a warning for the direct call to the pure virtual function, but not for the indirect call.

    ma lernt nie aus. die indireken calls sind aber gscheit gefährlich würd i mal sagen =[ so ähnlich dürfte der "pure virtual function call" im avid zustande gekommen sein, den i vor a paar wochen hatte 😃

    allerdings erklärt das noch immer nicht so ganz, dass auch dann nicht korrekt aufgelöst wird wenn die methode NICHT als abstrakt deklariert.



  • iko79 schrieb:

    allerdings erklärt das noch immer nicht so ganz, dass auch dann nicht korrekt aufgelöst wird wenn die methode NICHT als abstrakt deklariert.

    Wenn der Base-Konstruktor ausgeführt wird ist, hast du noch gar kein Derived-Objekt, nur ein Base-Objekt. Der Derived-"Teil" des Objekts wird erst danach konstruiert.

    Deswegen ist es ziemlich sinnlos, virtuelle Funktionen im CTor oder DTor aufzurufen. Das wurde hier schon hundertfach durchgekaut. Mich wundert, dass der IBM-Artikel das nicht mal erwähnt.



  • MFK schrieb:

    Wenn der Base-Konstruktor ausgeführt wird ist, hast du noch gar kein Derived-Objekt, nur ein Base-Objekt.

    das wundert mich insofern, als dass basisklassenkonstruktorer ja rekursiv von den übergeordneten aufgerufen werden und deshalb bereits bekannt ist, um welches objekt es sich handelt. also logisch find ich das ja nicht. wissen muss mans halt.

    MFK schrieb:

    Deswegen ist es ziemlich sinnlos, virtuelle Funktionen im CTor oder DTor aufzurufen.

    okay, das wusst' ich nicht. find ich aber ganzschön gefährlich.

    MFK schrieb:

    Das wurde hier schon hundertfach durchgekaut.

    hab ich nicht gelesen - hier am laufenden zu bleiben bzw. alles zu lesen was man bis zum eintritt ins forum verpasst hat geht einfach nicht 🙂

    dankedir!



  • iko79 schrieb:

    das wundert mich insofern, als dass basisklassenkonstruktorer ja rekursiv von den übergeordneten aufgerufen werden und deshalb bereits bekannt ist, um welches objekt es sich handelt. also logisch find ich das ja nicht. wissen muss mans halt.

    Bekannt ja, aber nicht konstruiert. Der Derived-Konstruktor ruft zuerst den Base-Konstruktor auf, bevor irgendwas anderes passiert. In Deinem Base-Konstruktor sind von Derived noch keine Member konstruiert worden, d.h. sie befinden sich alle in undefiniertem Zustand. Viel gravierender: Die Vtable von Derived (sofern bei der gegebenen Architektur vorhanden) ist auch noch nicht angelegt. Es kann also zur Laufzeit rein technisch schon kein Lookup gemacht werden. Rein logisch gesehen reicht aber eigentlich die Begründung "Derived existiert einfach noch nicht".

    okay, das wusst' ich nicht. find ich aber ganzschön gefährlich.

    Stimmt schon. Der MSVC warnt hier wenigstens oder schmeisst einen Linkerfehler.



  • iko79 schrieb:

    das wundert mich insofern, als dass basisklassenkonstruktorer ja rekursiv von den übergeordneten aufgerufen werden und deshalb bereits bekannt ist, um welches objekt es sich handelt.

    Diese Information mag vorhanden sein. Das ändert aber nichts daran, dass der Konstruktor von Derived zu diesem Zeitpunk noch nicht ausgeführt wurde.

    MFK schrieb:

    okay, das wusst' ich nicht. find ich aber ganzschön gefährlich.

    Die Alternative ist IMHO gefährlicher: Die Möglichkeit, eine Methode eines noch nicht konstruierten Objekts aufzurufen.



  • MFK schrieb:

    ...

    MFK schrieb:

    okay, das wusst' ich nicht. find ich aber ganzschön gefährlich.

    Die Alternative ist IMHO gefährlicher: Die Möglichkeit, eine Methode eines noch nicht konstruierten Objekts aufzurufen.

    Hi,

    wie macht Java das denn eigentlich ? Die "können" das doch, oder ?

    Gruß,

    Simon2.



  • C# kanns auch. Wird eben erst die Methodentabelle aufgebaut und dann der Rest konstruiert.



  • Helium schrieb:

    C# kanns auch. Wird eben erst die Methodentabelle aufgebaut und dann der Rest konstruiert.

    Genauergesagt werden erst Methodentabelle erstellt und Default-Konstruktionen durchgeführt (dazu gehören auch jene, die in der Klasse direkt mit Typ name = wert; aufgeführt sind), dann wird der Basisklassenkonstruktor durchgeführt, dann der eigene. Man kann in dieser Sprache also zumindest nachvollziehen, was zu dem Zeitpunkt definiert ist und was nicht.



  • LordJaxom schrieb:

    Helium schrieb:

    C# kanns auch. Wird eben erst die Methodentabelle aufgebaut und dann der Rest konstruiert.

    Genauergesagt werden erst Methodentabelle erstellt und Default-Konstruktionen durchgeführt (dazu gehören auch jene, die in der Klasse direkt mit Typ name = wert; aufgeführt sind), dann wird der Basisklassenkonstruktor durchgeführt, dann der eigene. Man kann in dieser Sprache also zumindest nachvollziehen, was zu dem Zeitpunkt definiert ist und was nicht.

    Ich verstehe das nicht ganz ... es wird IMMER erst ein (ggf. automatischer) Default-Ctor ausgeführt ?

    Magst Du das an einem simplen Beispiel mal erläutern ?

    Gruß,

    Simon2.



  • LordJaxom schrieb:

    Helium schrieb:

    C# kanns auch. Wird eben erst die Methodentabelle aufgebaut und dann der Rest konstruiert.

    Genauergesagt werden erst Methodentabelle erstellt und Default-Konstruktionen durchgeführt (dazu gehören auch jene, die in der Klasse direkt mit Typ name = wert; aufgeführt sind), dann wird der Basisklassenkonstruktor durchgeführt, dann der eigene. Man kann in dieser Sprache also zumindest nachvollziehen, was zu dem Zeitpunkt definiert ist und was nicht.

    Ich verstehe das nicht ganz ... es wird IMMER erst ein (ggf. automatischer) Default-Ctor ausgeführt ?

    Magst Du das an einem simplen Beispiel mal erläutern ?

    Gruß,

    Simon2.



  • java ruft immer den standard c-tor der oberklasse auf. wenn du also z.b. sowas hast

    class A extends B{
     A(){
      do();
     }
     do(){}
    }
    

    macht java da implizit ein

    class A extends B{
     A(){
      super();
      do();
     }
     do(){}
    }
    

    draus.



  • class B : public A
    {
       public:
         B() : A()
         {
            foo();
         }
         void foo()
         {}
    };
    

    Geht das nicht?



  • Simon2 schrieb:

    Ich verstehe das nicht ganz ... es wird IMMER erst ein (ggf. automatischer) Default-Ctor ausgeführt ?

    Magst Du das an einem simplen Beispiel mal erläutern ?

    Sagen wir es werden IMMER erst alle Objekte Default-Initialisiert. Da Objekte meistens Referenztypen sind heisst das eigentlich nichts weiter als dass die Referenz auf null gesetzt wird. Bei Wertetypen ist es IMHO ein Default (also 0 bei numerischen Typen).

    Hier mal ein Beispiel mit Initialisierungsreihenfolge:

    public class Derived : Base 
    {
    
        private MyRefType m_a; // implizit = null, (1)
        private List<MyRefType> m_b = new List<MyRefType>(); // explizit, (1)
    
        public Derived()
            // an dieser Stelle ist m_a == null und m_b schon != null und definiert
            : Base() // muss wie in C++ nur explizit geschehen wenn der Ctor Argumente verlangt, (2)
        {
            m_a = new MyRefType(); // (3)
        }
    }
    


  • javatyp schrieb:

    java ruft immer den standard c-tor der oberklasse auf.

    Das macht C++ auch, wenn du keinen anderen Basis-Ctor in der Initialisierungsliste angegeben hast. Aber das ist auch gar nicht Thema der Frage.

    Was würde Java bei so einem Konstrukt ausgeben?

    class A
    {
      void doit()
      { print("Basis"); }
    
      A()
      { doit(); }
    }
    
    class B extends A
    {
      void doit()
      { print("Abgeleitet"); }
    
      B()
      {}
    }
    

    (wie oben erkannt wurde, gibt C++ bei dieser Konstellation "Basis" aus, weil im A-Ctor der B-Anteil noch nicht existiert)



  • In C# käme "Abgeleitet" auf den Schirm. Allerdings nur wenn man die Methode in Basis noch virtual markiert.



  • CStoll schrieb:

    Was würde Java bei so einem Konstrukt ausgeben?

    class A
    {
      void doit()
      { print("Basis"); }
    
      A()
      { doit(); }
    }
    
    class B extends A
    {
      void doit()
      { print("Abgeleitet"); }
    
      B()
      {}
    }
    

    (wie oben erkannt wurde, gibt C++ bei dieser Konstellation "Basis" aus, weil im A-Ctor der B-Anteil noch nicht existiert)

    java ruft jeweils die methode doit der instanziierten klasse auf. denn genau wie LordJaxom bereits gesagt hat, erstellt java zunächst alle methodentabellen und ruft erst dann die konstruktoren auf. weshalb sowas wie ein "pure virtual function call" (bzw. abstract in java termen) theoretisch gar nicht auftreten kann.



  • CStoll schrieb:

    javatyp schrieb:

    java ruft immer den standard c-tor der oberklasse auf.

    Das macht C++ auch, wenn du keinen anderen Basis-Ctor in der Initialisierungsliste angegeben hast. Aber das ist auch gar nicht Thema der Frage....

    Doch - schon Thema meiner Frage (und damit ein wenig OT - ich hoffe, Ihr verzeiht mir).

    @Lord: Danke.
    Ja, man hat in Java eigentlich nur Referenzen und primitive Typen in der Hand ... aber wie ist das mit "aggregierten Basisklassen" bei der Vererbung ?

    Meine Frage ging nämlich eigentlich eher in eine andere Richtung: Was, wenn ich den DefaultCtor "privatisiere", weil das Teil nur über meinen "parametrisierten Ctor" erzeugt werden soll ? Geht das auch (wobei ich dann explizit das passende super() aufrufen muss) ?
    Oder bedeutet "default-konstruiert" evtl. nicht unbedingt, dass der "Default-Ctor" aufgerufen wird, sondern eher etwas Ähnliches, was der Compiler für mich macht ?

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Meine Frage ging nämlich eigentlich eher in eine andere Richtung: Was, wenn ich den DefaultCtor "privatisiere" [...]

    dann schmeisst dir der compiler nen error um die ohren, weil der implizite konstruktor der oberklasse (oder basisklasse, wie man es auch immer nennen mag) nicht sichtbar ist.



  • achso, was aber gehen sollte ist, wenn der erste aufruf im default konstruktor deiner abgeleiteten klassen einen parametrisierten konstruktor der basisklasse aufruft, dann sollte das ganze eigentlich gehen.


Anmelden zum Antworten