Zugriff auf Variable von Basisklasse geht nicht



  • Code kaputt! Warum?

    Ich versuche gerade wieder etwas auf C++ umzusteigen und haenge nun schon bei ein paar Zeilen C++ - Vererbung, Funktionsdeklaration mit virtual, Zugriff auf Variable in Basisklassenobjekt von Childklassenobjekt - ein Klassiker, wie ich mich erinnere..

    1. Der Code unten kompiliert (gcc auf cygwin, liegt's daran?), aber der Linker gibt mir einen fuer mich unverstaendlichen Fehler und somit bleibe ich bei ungelinkten Objekten - warum?

    $ make clean && make
    rm -f virtualdestructor.o virtualdestructor.exe *~ core
    g++ -c -o virtualdestructor.o virtualdestructor.cpp
    g++ -o virtualdestructor virtualdestructor.o -lm
    virtualdestructor.o:virtualdestructor.cpp:(.rdata_ZTV4BaseIiE[vtable for Base]+0x10): undefined reference to `Base::setValue(int) ' virtualdestructor.o:virtualdestructor.cpp:(.rdata_ZTV4BaseIiE[vtable for Base<int>]+0x14): undefined reference to `Base<int>::getValue()'
    collect2: ld returned 1 exit status
    make: *** [virtualdestructor] Error 1

    Wie macht man das normalerweise, was habe ich bei meinem Prg vergessen?

    2. Desweiteren sobald ich

    Base<T>::
    

    weglasse meckert er, dass ihm "value" komplett unbekannt ist. Dabei ist "value" doch als "protected" deklariert?! Vllt fehlt ja was an der template-Schreibweise. Auf diese moechte ich aber eig nicht verzichten, bzw damit wollte ich eig ja rumspielen.
    Danke im voraus. 🤡

    Ich habe folgendes Beispiel geschrieben:

    #include <iostream>
    
    template<class T> class Base;
    template<class T> class Derived;
    
    /*
      base class
    //*/
    template<class T>
    class Base
    {
    protected:
      T value;
    
    public:
      Base();
      virtual ~Base() = 0; // makes the class abstract!
    
      /*
        F U N C T I O N S
      //*/
    
      virtual void setValue(T val);
      virtual T getValue();
    };
    
    template<class T>
    Base<T>::Base()
    {}
    
    template<class T>
    Base<T>::~Base()
    {}
    
    /*
      some derived class
    //*/
    template<class T> 
    class Derived : public Base<T>
    {
    public:
      Derived();
      ~Derived();
    
      void setValue(T val);
      T getValue();
    };
    
    template<class T>
    Derived<T>::Derived()
    {}
    
    template<class T>
    Derived<T>::~Derived()
    {}
    
    template<class T>
    void Derived<T>::setValue(T val)
    {
      Base<T>::value = val;
    }
    
    template<class T>
    T Derived<T>::getValue()
    {
      return Base<T>::value;
    }
    
    /*
      some main()
    //*/
    int main()
    {
      // init
      Derived<int> d;
    
      // intput
      std::cout << "set a value" << std::endl;
      d.setValue(123);
    
      // output
      std::cout << "the value was: " << d.getValue() << std::endl;
    
      std::cout << "READY.\n" << std::endl;
      return 0;
    }
    


  • Hallo,

    Das ist doch ganz eindeutig. Du hast setValue und getValue von Base nicht definiert. Da sie nicht pure virtual sind mußt du das.



  • Ok, stimmt, damit kompiliert es.

    Warum muss ich "value" eigentlich als

    Base<T>::value
    

    angeben? Ich hab das doch in der Base-Klasse schon als "protected" definiert?!

    Ausserdem warum bekomme ich eig einen unverstaendlichen Linkererror und nicht gleich einen Compilererror (waere halt etwas einfacher, oder?)?

    Danke 🙂



  • Fabeltier schrieb:

    Warum muss ich "value" eigentlich als

    Base<T>::value
    

    angeben? Ich hab das doch in der Base-Klasse schon als "protected" definiert?!

    das hat mit protected nichts zu tun. Du musst es qualifizieren damit der Compiler kapiert was du meinst. Könnte ja sein, dass du irgendwoander Base für einen bestimmten Typ (z.B. int) spezialisierst, und dann hat der Ausdruck "value" in Derived<int> eine völlig andere Bedeutung. Eine Alternative zu Base<T>::value wäre this->value

    Ausserdem warum bekomme ich eig einen unverstaendlichen Linkererror und nicht gleich einen Compilererror (waere halt etwas einfacher, oder?)?
    Danke 🙂

    Der Compiler merkt nicht dass da was im Argen ist. Er sieht nur dass Base<T> diese Funktionen haben soll, dass sie nicht in der gleichen Übersetzungseinheit definiert werden ist nicht sein Bier. Du könntest sie theoretisch in einer anderen ÜE definieren (okay, bei templates etwas schwierig aber das ist ne andere Geschichte) und die dann zu deinem ganzen Geraffel dazulinken - dann wäre auch der Linke glücklich.



  • @Fabeltier:
    In deinem Beispielcode brauchst du gar nicht set/get virtual zu deklarieren und in Derivied auch nicht. Es reicht wenn sie in der Basisklasse sind. Die abgeleitete Klasse bekommt sie ja ehe vererbt und value steckt ja auch in Base drin.



  • Ok, danke, klar den this Zeiger gab's ja auch noch, dachte nur evtl geht's auch ohne. Das hilft mir jedenfalls weiter, danke fuer die informativen Antworten!!

    Zur zweiten Frage (warum Linkererror und kein Compilererror), haette mich halt noch interessiert, ob es da evtl irgendwelche Moeglichkeiten gaebe, etwa das ganze so hinzudeklarieren, dass eben schon der Compiler fehlschlaegt und nicht erst der Linker, evtl eine Technik etwa.. Danke, super Antworten! 👍



  • Fabeltier schrieb:

    warum Linkererror und kein Compilererror

    Dadurch das du die Funktion nur deklariert hast, hast du sie dem Compiler bekannt gemacht. Dh er geht davon aus, dass sie irgendwo definiert ist, sei es in einer anderen .cpp oder externen Bibliothek.
    Dann kommt der Linker ins Spiel und setzt alle Dateien zusammen und kann aber die dem Compiler bekannt gemachte Definition der Funktion nicht finden und meckert deshalb.
    Hoffe mal das stimmt als Begründung sowei 🙂



  • KasF schrieb:

    @Fabeltier:
    In deinem Beispielcode brauchst du gar nicht set/get virtual zu deklarieren und in Derivied auch nicht. Es reicht wenn sie in der Basisklasse sind. Die abgeleitete Klasse bekommt sie ja ehe vererbt und value steckt ja auch in Base drin.

    Hallo und nochmal danke KasF. Ja, stimmt, aber dann haette ich kein Beispiel um mein Problem zu zeigen 😉
    Das sollte nur ein Demo sein, welches mir einerseits dazu dient hier mein Problem zu demonstrieren und mir andererseits erhalten bleiben soll als Notiz mit Kommentaren, eben zur Syntax bei virtuellen und rein virtuellen Funktionen.


Anmelden zum Antworten