Member abstrakter basisklasse in abgeleiteter zugänglich machen



  • Ich steh komplett auf dem schlauch und verstehe absolut nicht warum folgendes nicht geht. Ich habe Member in einer basisklasse. Soweit ich weiß sollte man basisklassen (wenn sie abstrakt sind) nicht mit konstruktor aufrufen bzw. die member so nicht setzen. deswgen leite ich ab von der basisklasse und setze da über eine initialisierungsliste. Ich dachte es funktinoiert so....aber mitdem code:

    #include <iostream>
    
    class Affe
    {
       public:
    
            protected:
                    int var1;      
    };
    
    class Bear : public Affe
    {
    
            public:
                    Bear(int var_) : var1(var_) {};
                    void foo() {
                            std::cout << var1 << std::endl;       
                    };
    };
    
    int main()
    {
        Bear b = Bear(3);
        b.foo();
    }
    

    heißt es dass es keinen feldnamen var1 gibt. Liegt das daran dass Bear noch keinen member abgeleitet hat und über die liste schon versucht wird zu setzen ? Wenn ja - wie kann ich das umgehen?



  • Ok...also anscheinend liegt es an den templates.

    warum geht das hier

    #include <iostream>
    
    class Affe
    {
       public:
            Affe(int var_) : var1(var_) {}
            protected:
                    int var1;  
                    int var2;    
    };
    
    class Bear : public Affe
    {
    
            public:
                    Bear(int var_) : Affe(var_) {var2 = -2;};
                    void foo() {
                            std::cout << var1 << std::endl;       
                            var1 = 3;
                            std::cout << var1 << std::endl;
                            std::cout << var2 << std::endl;
                    };
    };
    
    int main()
    {
        Bear b = Bear(5);
        b.foo();
    }
    

    aber das hier nicht?

    #include <iostream>
    
    template <class T>
    class Affe
    {
       public:
            Affe<T>(int var_) : var1(var_) {}
            protected:
                    int var1;  
                    int var2;    
    };
    
    template<class T>
    class Bear : public Affe<T>
    {
    
            public:
                    Bear<T>(int var_) : Affe<T>(var_) {var2 = -2;};
                    void foo() {
                            std::cout << var1 << std::endl;       
                            var1 = 3;
                            std::cout << var1 << std::endl;
                            std::cout << var2 << std::endl;
                    };
    };
    
    int main()
    {
        Bear<int> b = Bear<int>(5);
        b.foo();
    }
    
    main.cpp: In constructor »Bear<T>::Bear(int)«:
    main.cpp:18: Fehler: »var2« wurde in diesem Gültigkeitsbereich nicht definiert
    main.cpp: In member function »void Bear<T>::foo()«:
    main.cpp:20: Fehler: »var1« wurde in diesem Gültigkeitsbereich nicht definiert
    main.cpp:23: Fehler: »var2« wurde in diesem Gültigkeitsbereich nicht definiert
    


  • So sollte es was werden:

    Affe<T>::var1 = 2;
    

    btw wo ist deine abstakte Basisklasse?



  • Eh wie meinst du das mit Affe<T>::var1 = 2;
    wo soll das stehen?



  • Kannn ich denn nicht von template-basierten klassen auf member zugreifen?

    muss ich dann jedesmall den klassennamen::member angehen?



  • template<class T> 
    class Bear : public Affe<T> 
    { 
    
            public: 
                    Bear<T>(int var_) : Affe<T>(var_) {}
                    void foo() { 
                            std::cout << Affe<T>::var1 << std::endl;       
                            Affe<T>::var1 = 3; 
                            std::cout << Affe<T>::var1 << std::endl; 
                            std::cout << Affe<T>::var2 << std::endl; 
                    }; 
    };
    


  • danke dir aber muss ich dann wirklich IMMER den klassennamen angeben? geht das nicht anders auch?



  • template<typename T>
    class Bear : public Affe<T> {
      using Affe<T>::var2; // <--
    
    public:
      void foo() {
        var2 = 2;
      }
    };
    


  • ok vielen dank. jetzt würde mir aber glaube ich eine erklärung gut tun...warum gibt es da einen unterschied und warum geht das nur so? tut mir leid für die dumme frage...aber ich verstehe nicht warum es bei templates einen unterschied macht.

    danke für weitere erklärungen



  • Du kennst es so, wenn eine Klasse eine andere Klasse erweitert, dann kannst du Member der Basisklasse zugreifen, weil die Erweiterung in gleichen Gültikeitsbereich stattfindet. Die Instanzierung eines Typens hat ihren eigenen Gültigkeitsbereich. Wenn du aber eine Klassentemplate schreibst, bist du selbst in keine Instanz eines Typen drin, daher muss diese Information expliziet angeben.



  • Kurze Antwort: Steht so im Standard.

    Ich nehme an, der Grund sind Spezialisierungen und ungewollte und -übersichtliche Nebeneffekte. Nimm etwa

    typedef double value_t;
    
    template<typename T> struct A {};
    template<typename T> struct B : public A<T> {
      value_t x;
    };
    
    template<> struct A<int> { typedef int value_t; };
    
    // ...
    
    B<int> b; // b.x bleibt double.
    

    Der Compiler geht davon aus, dass der Autor von B sich darauf verlässt, dass value_t die im globalen Namensraum definierten Eigenschaften besitzt. Wenn eine Überdeckung durch bestimmte Eigenschaften von A gewünscht ist, kann es halt per using-Direktive erklärt werden.



  • -.-



  • @seldon
    Ich meine gelesen zu haben, dass man class anstatt typename vorziehen sollte wenn man weiß, das eine Klasse übergeben wird.



  • Kóyaánasqatsi schrieb:

    @seldon
    Ich meine gelesen zu haben, dass man class anstatt typename vorziehen sollte wenn man weiß, das eine Klasse übergeben wird.

    Spielt überhaupt keine Rolle. Sind völlig äquivalent.



  • Nahezu äquivalent. Man kann etwa

    template<template<typename> class TT>
    struct A { };
    

    nicht als

    template<template<typename> typename TT> // Fehler!
    struct A { };
    

    schreiben. Ansonsten ist es Geschmackssache, welches Schlüsselwort man benutzt - ich bevorzuge typename, weil es mir klarer erscheint (die Vorlage wird ja durch die Benutzung von "class" nicht auf Klassen beschränkt), aber man könnte mit hinreichend mathematischer Anschauungsweise den Standpunkt vertreten, dass Basistypen auch Klassen (von Objekten) sind.

    class zu schreiben, um zu signalisieren, dass man eine Klasse erwartet, scheint mir aber nicht sonderlich sinnvoll - man erwartet ja in so einem Fall nicht irgendeine Klasse, sondern eine Klasse, die bestimmte Anforderungen, die die Vorlage benötigt, erfüllt. Das muss man dann eh sinnvoll dokumentieren.


Anmelden zum Antworten