abgeleitete Klasse variable aus der Basisklasse nicht deklariert



  • Hey Leute,

    Übe gerade ein bisschen Cpp und kann mir den Grund für die Fehlermeldung des Compilers nicht erklären:
    |71|error: ‘first’ was not declared in this scope|
    Wenn ich aber stattdessen einfach this->first schreibe, läuft alles.
    Warum ist das so? Schließlich ist Set doch von der Klasse Liste abgeleitet und sollte dadruch Zugriff auf die public und protected Bestandteile haben. Und mit this-> ändere ich ja auch nichts an den Zugriffsrechten oder ähnliches, oder?

    Danke für eure Hilfe und Tipps 🙂

    #include <iostream>
    
    template <typename T>
    struct Knoten{
    	T value;
    	Knoten<T> *next;
    
    	Knoten(T v = 0){
    		next = NULL;
    		value = v;
    	}
    };
    
    template <typename T>
    class Liste{
    protected:
    	Knoten<T> *first;
    	int size;
    public:
    	Liste(){
    		size = 0;
    		first = new Knoten<T>();
    	}
    	~Liste(){
    		while(first != NULL){
    			Knoten<T> *k = first->next;
    			delete first;
    			first = k;
    		}
    	}
    	void insert(T v){
            Knoten<T> *temp, *temp2;
            temp = first;
            while(temp != NULL && v > temp->value){
                temp2 = temp;
                temp = temp->next;
            }
            if(temp == NULL){
                temp2->next = new Knoten<T>(v);
            } else{
                temp2->next = new Knoten<T>(v);
                temp2->next->next = temp;
            }
    	}
    	void printListe(){
            Knoten<T> *temp;
            temp = first;
            while(temp != NULL){
                std::cout << temp->value << std::endl;
                temp = temp->next;
            }
    	}
    	T operator[](const int &pos){
            Knoten<T> *temp = first;
            for(int i = 0; i < pos && temp != NULL; i++){
                temp = temp->next;
            }
            if(temp == NULL){
                throw "Out Of Range";
            } else{
                return temp->value;
            }
    	}
    };
    
    template <typename T>
    class Set : public Liste<T>{
    public:
        void insert(T v){
            Knoten<T> *temp, *temp2;
            temp = first;
            while(temp != NULL && v > temp->value){
                temp2 = temp;
                temp = temp->next;
            }
            if(temp == NULL){
                temp2->next = new Knoten<T>(v);
            } else if(temp->value != v){
                temp2->next = new Knoten<T>(v);
                temp2->next->next = temp;
            }
        }
    };
    
    int main(){
        Set<double> test;
        test.insert(2.2);
        test.insert(5.5);
        test.insert(7.7);
        test.insert(4.4);
        test.insert(10.1);
        test.insert(7.7);
        test.printListe();
        std::cout << "Position 3: " << test[3] << std::endl;
        std::cout << "Position 0: " << test[0] << std::endl;
    
        return 0;
    }
    


  • Und mit this-> ändere ich ja auch nichts an den Zugriffsrechten oder ähnliches, oder?

    Nein, aber du gibst einen expliziten Verweis auf die Klassenvariable. Schau dir mal deinen Funktionscode an:

    void insert(T v){
            Knoten<T> *temp, *temp2;
            temp = first;
            while(temp != NULL && v > temp->value){
                temp2 = temp;
                temp = temp->next;
            }
            if(temp == NULL){
                temp2->next = new Knoten<T>(v);
            } else if(temp->value != v){
                temp2->next = new Knoten<T>(v);
                temp2->next->next = temp;
            }
    

    Wenn der Zugriff ohne this-> möglich wäre, würde eine Einschränkung resultieren: Du könntest keine lokale Variable mit dem Namen first anlegen, z.B

    void insert(T v){
            Knoten<T> *temp, *temp2;
            int first = 10;
    


  • Aber das würde ja bedeuten, dass bei diesem Dekorierer Entwurfsmuster ein this-> vor dem dekoriert stehen müsste, schließlich könnte ich in den Klassen Milchschaum und Schoko sonst keine Variable mit der Bezeichnung dekoriert erstellen, oder?

    #include <iostream>
    #include <string>
    using namespace std;
    
    class Kaffee {
    public:
    	virtual ~Kaffee() {}
    	virtual int preis() = 0;
    	virtual std::string rechnung() = 0;
    };
    
    class Espresso : public Kaffee {
    public:
    	int preis(){
    		return 240;
    	}
    	std::string rechnung(){
    		return "Espresso: 240\n";
    	}
    };
    
    class Hausmischung : public Kaffee {
    public:
    	int preis(){
    		return 180;
    	}
    	std::string rechnung(){
    		return "Hausmischung: 180\n";
    	}
    };
    
    class Zutat : public Kaffee {
    protected:
    	Kaffee *dekoriert;
    
    public:
    	Zutat(Kaffee *k){
    		dekoriert = k;
    	}
    };
    
    class Milchschaum : public Zutat {
    public:
    	Milchschaum(Kaffee *k):Zutat(k){
    
    	}
    	~Milchschaum(){
    		std::cout << "~Milchschaum\n";
    		delete dekoriert;
    	}
    	int preis(){
    		return 20 + dekoriert->preis();
    	}
    	std::string rechnung(){
    		return dekoriert->rechnung() + "Milchschaum: 20\n";
    	}
    };
    
    class Schoko : public Zutat {
    public:
    	Schoko(Kaffee *k):Zutat(k){
    
    	}
    	~Schoko(){
    		std::cout << "~Schoko\n";
    		delete dekoriert;
    	}
    	int preis(){
    		return 10 + dekoriert->preis();
    	}
    	std::string rechnung(){
    		return dekoriert->rechnung() + "Schoki: 10\n";
    	}
    };
    
    class Keks : public Zutat {
    public:
    	Keks(Kaffee *k):Zutat(k){
    
    	}
    	virtual ~Keks(){
    		std::cout << "~Keks\n";
    		delete dekoriert;
    	}
    	int preis(){
    		return 15 + dekoriert->preis();
    	}
    	std::string rechnung(){
    		return dekoriert->rechnung() + "Keks: 15\n";
    	}
    };
    
    int main(void) {
    
    	Kaffee *k = new Schoko(
    				new Keks(
    					new Milchschaum(
    						new Espresso())));
    
    	cout << k->rechnung();
    	cout << k->preis() << endl << endl;
    	delete k;
    	cout << endl << endl;
    
    	k = new Schoko(
    			new Schoko(
    				new Milchschaum(
    					new Keks(
    						new Espresso()))));
    
    	cout << k->rechnung();
    	cout << k->preis() << endl << endl;
    	delete k;
    	cout << endl << endl;
    
    	return 0;
    }
    


  • So, ich habe jetzt einfach mal in das DekoriererMuster templates reingebracht.
    Das hatte zur folge, dass ich zum Zugriff von einer abgeleiteten Klasse auf eine Variable in der Basisklasse jetzt this benutzen muss.

    template <typename T>
    class Schoko : public Zutat<T> {
    public:
    	Schoko(Kaffee *k):Zutat<T>(k){
    
    	}
    	~Schoko(){
    		std::cout << "~Schoko\n";
    		delete this->dekoriert;
    	}
    	int preis(){
    		return 10 + this->dekoriert->preis();
    	}
    	std::string rechnung(){
    		return this->dekoriert->rechnung() + "Schoki: 10\n";
    	}
    };
    


  • GrüneBanane schrieb:

    Wenn der Zugriff ohne this-> möglich wäre, würde eine Einschränkung resultieren: Du könntest keine lokale Variable mit dem Namen first anlegen, z.B

    void insert(T v){
            Knoten<T> *temp, *temp2;
            int first = 10;
    

    Sorry, Deine Erklärung ist leider falsch. Beim Zugriff auf eine Membervariablen aus einer Memberfunktion ist die explizite Dereferenzierung des Zeigers this nicht notwendig. Auch dann nicht, wenn die Membervariable Teil einer Basisklasse ist.

    Korrekt aber ist, daß die Derefenzierung erforderlich ist, wenn es auch eine lokale Variable, mit dem selben Namen gibt.

    Hier haben wir es mit aber mit Klassentemplates zu tun. Aus einem Grund, den ich jetzt allerdings nicht kenne, verlangt z.B. Gnu-C beim Zugriff auf Memberfunktionen oder -variablen von Basisklassen die explizite Dereferenzierung des Zeigers this auch, wenn es keine lokale Variable mit dem selben Namen gibt. Gleiches gilt auch für Aufrufe von Memberfunktionen einer Basisklasse.

    Warum das so ist, weiß ich nicht. Meine alten Borland-compiler können sowas problemlos übersetzen.

    mfg Martin



  • mgaeckler schrieb:

    Hier haben wir es mit aber mit Klassentemplates zu tun. Aus einem Grund, den ich jetzt allerdings nicht kenne, verlangt z.B. Gnu-C beim Zugriff auf Memberfunktionen oder -variablen von Basisklassen die explizite Dereferenzierung des Zeigers this auch, wenn es keine lokale Variable mit dem selben Namen gibt. Gleiches gilt auch für Aufrufe von Memberfunktionen einer Basisklasse.

    Warum das so ist, weiß ich nicht. Meine alten Borland-compiler können sowas problemlos übersetzen.

    Das ist verlangt, weil es der Standard so sagt. Borland - wie teilweise auch MSVC - sind da nicht konform.
    Der exakte Grund ist hier ausführlich beschrieben: http://stackoverflow.com/a/4643295



  • Ok, danke. Damit hat sich meine Frage aufgeklärt 🙂


Anmelden zum Antworten