Index- und Zuweisungsoperator überladen?



  • Hallo ich bin mir gerade ein Klasse für eine Verkette Liste am schreiben.
    Jetzt möchte ich gerne über den Indexoperator direkt auf ein Element zugreifen, das funktioniert wunderbar.
    Aber jetzt möchte ich aber auch mit dem Indexoperator ein Element direkt auswählen und diese mit dem Zuweisungsoperator überschreiben und da komme ich nun zu meinem Problem:
    Wie überlade ich Indexoperator und Zuweisungsoperator gleichzeitig?



  • Du musst die beiden Operatoren nicht "gleichzeitig" überladen, da deren Aufgaben nicht die gleiche Klasse betreffen.

    Mit dem Indexoperator [] greifst du sehrwahrscheinlich auf Member der Klasse zu, richtig? Du willst also diesen Membern etwas zuweisen. Dann wird der Zuweisungsoperator des jeweiligen Membertyps aufgerufen, das ist nicht mehr die Aufgabe der Klasse.

    Um Zuweisungen durchführen zu können, gibt man am besten eine Referenz auf das betreffende Objekt zurück.



  • Nein das ist ja mein Problem, also da sist die Klasse:

    #include <iostream>
    
    using namespace std;
    
    template<class T>
    class MyList
    {
    private:
    	struct Node
    	{
    		Node *next;			//Nächstes Element
    		Node *prevouis;		//Voriges Element
    		T value;			//Gespeichterter Wert
    	};
    
    	Node *_first;			//Erstes Element
    	Node *_last;			//Letztes Element
    	int _iCount;			//Anzahl der Elemente
    
    public:
    
    	MyList()
    	{
    		_first = NULL;
    		_last = NULL;
    		_iCount = 0;
    	}
    
    	~MyList()
    	{
    		this->Clear();
    	}
    
    	//Fügt ein neues Element der Liste hinzu
    	void Add(T value)
    	{
    		Node *newNode = new Node();
    		newNode->value = value;
    		newNode->next = NULL;
    		newNode->prevouis = NULL;
    
    		if(_iCount == 0)
    		{
    			//Liste ganz neu erstellen:
    			_first = newNode;
    			_last = newNode;
    		}
    		else
    		{
    			//Neues Element einfügen:
    			newNode->prevouis = _last;
    			_last->next = newNode;
    			_last = newNode;
    		}
    
    		_iCount++;
    	}
    
    	//Liste leeren
    	void Clear()
    	{
    		Node *cache = _first;
    		for(Node *current = _first; cache != NULL; current = cache)
    		{
    			cache = current->next;
    			free(current);
    		}
    		_first = NULL;
    		_last = NULL;
    		_iCount = 0;
    	}
    
    	//Gibt die Anzahl der Elemente zurück
    	int Count()
    	{
    		return _iCount;
    	}
    
    	T operator[](int index)
    	{
    		Node* current = _first;
    		int x = 0;
    
    		while(x < index)
    		{
    			current = current->next;
    			x++;
    		}
    
    		return current->value;
    	}
    
    };
    

    Und wenn ich jetzt das mache:

    MyList<int> myList;
    	myList.Add(47);
    	myList.Add(9);
    	myList.Add(10);
    	myList.Add(3);
    
    	myList[1] = 10;
    

    sagt mir der Compiler:
    error C2106: '=': Linker Operand muss ein L-Wert sein



  • Du bist ganz eindeutig ein Troll, wenn nicht RTFM und gib T& statt T im op[] zurück!



  • Du musst eine Referenz, also T& als Rückgabewert haben.

    Du bist dir aber schon bewusst, dass "Random Access" in einer Liste eine lineare Komplexität hat? Also je weiter hinten das Element ist, desto länger braucht der Zugriff. Nicht gerade das Wahre. Eventuell solltest du dich mit Iteratoren vertraut machen und so was ähnliches implementieren.

    Abgesehen davon würde ich Header und Implementation trennen, so lange Inline-Funktionen sind unübersichtlich -> auslagern in CPP-Datei.



  • Ich bin ein Troll?? Na denn, wenn du das sagst.
    ich frage mich sowieso warum der Administrator zulässt das Unregistrierter Nutzer hier schreiben dürfen..



  • Nexus schrieb:

    Abgesehen davon würde ich Header und Implementation trennen, so lange Inline-Funktionen sind unübersichtlich -> auslagern in CPP-Datei.

    dazu hatte ich schon ein Thema hier und raus kam Template + *.h + *.cpp = Viel ärger.. das kannste voll vergessen.



  • lord_fritte schrieb:

    Ich bin ein Troll?? Na denn, wenn du das sagst.
    ich frage mich sowieso warum der Administrator zulässt das Unregistrierter Nutzer hier schreiben dürfen..

    Weil die unregistrierten Nutzer offensichtlich mehr drauf haben als du, wenn dann würde er wohl eher dich sperren als das gesamte Potential der Unregistrierten auszuschließen.

    Hab ich dir dein Problem genannt oder nicht?

    Offensichtlich bist du ein Troll, sonst würdest du nicht so ausfallend werden, schließlich willst du was von uns und nicht umgekehrt.



  • lord_fritte schrieb:

    Nexus schrieb:

    Abgesehen davon würde ich Header und Implementation trennen, so lange Inline-Funktionen sind unübersichtlich -> auslagern in CPP-Datei.

    dazu hatte ich schon ein Thema hier und raus kam Template + *.h + *.cpp = Viel ärger.. das kannste voll vergessen.

    Ist kein Grund es in die Klassendeklaration zu schreiben, du kannst es auch darunter schreiben, oder in eine Datei und diese am Ende inkludieren.

    Hoppla jetzt hat ein Unregistrierter schon wieder mehr Ahnung wie du...



  • Meine Güte, hört doch mit diesen Kindereien auf, wer hier mehr Ahnung hat und wer ein Troll ist.

    lord_fritte schrieb:

    ich frage mich sowieso warum der Administrator zulässt das Unregistrierter Nutzer hier schreiben dürfen..

    Wenn es dich wirklich interessiert, darfst du gerne die Diskussion darüber nachlesen (ist übrigens nur eine von vielen).

    lord_fritte schrieb:

    dazu hatte ich schon ein Thema hier und raus kam Template + *.h + *.cpp = Viel ärger.. das kannste voll vergessen.

    Stimmt, es handelt sich ja um ein Template, da habe ich nicht mehr dran gedacht. Trotzdem würde ich wenigstens die Klasse nur mit den Methodendeklarationen definieren, und die Methoden ihrerseits ausserhalb der Klasse. Um auch bei Templates eine saubere Trennung zu haben, kann man ja einen weiteren Header mit der Implementation erstellen.



  • Nexus schrieb:

    Meine Güte, hört doch mit diesen Kindereien auf, wer hier mehr Ahnung hat und wer ein Troll ist.

    Also ich zu meinem Teil, ich bin ein Anfänger ^^
    und @Troll-Detektor auf das T und T& bin ich echt nicht gekommen, sorry.

    Nexus schrieb:

    Stimmt, es handelt sich ja um ein Template, da habe ich nicht mehr dran gedacht. Trotzdem würde ich wenigstens die Klasse nur mit den Methodendeklarationen definieren, und die Methoden ihrerseits ausserhalb der Klasse. Um auch bei Templates eine saubere Trennung zu haben, kann man ja einen weiteren Header mit der Implementation erstellen.

    Also wenn ich das so versteh das ich beides in 2 Dateien trennen soll, das habe ich schon versucht, es geht nicht.
    Definition der Klasse und Methodendeklarationen müssen in der selben Datei sein, sonst geht garnichts mehr.

    Aber was ist denn so schlimm daran ob die Methodendeklarationen in der Klassendefinition sind oder nicht?



  • lord_fritte schrieb:

    Also wenn ich das so versteh das ich beides in 2 Dateien trennen soll, das habe ich schon versucht, es geht nicht.
    Definition der Klasse und Methodendeklarationen müssen in der selben Datei sein, sonst geht garnichts mehr.

    Man müsste die andere Datei eben schon einbinden 😉
    Du kannst Folgendes tun:
    Header (Klassendefinition, Methoden- und Memberdeklaration)

    // MyClass.hpp
    template <typename T>
    class MyClass
    {
        void Func();
    };
    
    #include "MyClass_impl.hpp"
    

    Implementierung (hauptsächlich Methodendefinition)

    // MyClass_impl.hpp
    template <typename T>
    void MyClass<T>::Func()
    {
    
    }
    

    lord_fritte schrieb:

    Aber was ist denn so schlimm daran ob die Methodendeklarationen in der Klassendefinition sind oder nicht?

    Erstens mal sollten längere Funktionen nicht inline sein, weil ihr Funktionsrumpf bei jedem Aufruf in den Code kopiert wird (auch wenn das durch viele Compiler optimiert wird). Zweitens wirfst du so die Übersichtlichkeit über Bord. Der Header dient als Schnittstelle und sollte als solche auch schnellen Überblick über die Funktionalität geben.



  • Nexus schrieb:

    Erstens mal sollten längere Funktionen nicht inline sein, weil ihr Funktionsrumpf bei jedem Aufruf in den Code kopiert wird (auch wenn das durch viele Compiler optimiert wird).

    Stimmt nicht inline ist eine Empfehlung für den Compiler, kein muss.

    Zweitens wirfst du so die Übersichtlichkeit über Bord. Der Header dient als Schnittstelle und sollte als solche auch schnellen Überblick über die Funktionalität geben.

    Das ist ein Argument 👍



  • Ich habs jetzt so:

    //MyClass.hpp
    #include <iostream>
    
    template<typename T> // egal ob template<typename T> oder template<class T>
    MyClass
    {
    public:
        void Func();
    }; //Zeile 8
    
    #include "MyList2.hpp"
    
    //MyClass_impl.hpp
    #include <iostream>
    
    template <typename T>
    void MyClass<T>::Func() // Zeile2
    {
    
    }
    

    Das ergibt:

    Fehler	1	error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt. MyClass.hpp: Zeile 8
    Fehler	2	error C2998: 'int MyClass': Kann keine Vorlagendefinition sein	MyClass.hpp: Zeile 8
    Fehler	3	error C2143: Syntaxfehler: Es fehlt ';' vor '<'	MyClass_impl.hpp: Zeile 4
    Fehler	4	error C2182: 'MyClass': Unzulässige Verwendung des Typs 'void'	MyClass_impl.hpp: Zeile 4
    Fehler	5	error C2086: 'int MyClass': Neudefinition	MyClass_impl.hpp: Zeile 4
    Fehler	6	error C2988: Unerkannte Vorlagendeklaration/-definition	MyClass_impl.hpp: Zeile 4
    Fehler	7	error C2059: Syntaxfehler: '<'	MyClass_impl.hpp: Zeile 4
    Fehler	8	error C2039: 'Func': Ist kein Element von '`global namespace''	MyClass_impl.hpp: Zeile 4
    

    Das sind die selben Fehler wie ich schon hatte, das läßt sich einfach nicht trennen!!



  • Troll-Detektor schrieb:

    Nexus schrieb:

    Erstens mal sollten längere Funktionen nicht inline sein, weil ihr Funktionsrumpf bei jedem Aufruf in den Code kopiert wird (auch wenn das durch viele Compiler optimiert wird).

    Stimmt nicht inline ist eine Empfehlung für den Compiler, kein muss.

    Nein, tatsächlich? Rate mal, aus welchem Grund ich eine Klammerbemerkung eingefügt habe... 🙄



  • @ lord_fritte:
    Hast du den Header auch richtig eingebunden? Heisst der "MyList2.hpp"?

    Versuch mal, den Code im Implementations-Header gleich unter den Deklarations-Header zu setzen (in die gleiche Datei) und sag, ob der Fehler immer noch auftritt. Wenn nicht, hast du falsch inkludiert ( #include macht reine Textersetzung), wenn doch, poste noch einmal den zusammenhängenden Code.



  • Nexus schrieb:

    @ lord_fritte:
    Hast du den Header auch richtig eingebunden? Heisst der "MyList2.hpp"?

    Versuch mal, den Code im Implementations-Header gleich unter den Deklarations-Header zu setzen (in die gleiche Datei) und sag, ob der Fehler immer noch auftritt. Wenn nicht, hast du falsch inkludiert ( #include macht reine Textersetzung), wenn doch, poste noch einmal den zusammenhängenden Code.

    Sobald ich beides in die selbe Datei packe läuft es ohne Fehler!!


  • Administrator

    wie wäre es mit class MyClass statt MyClass ? 🙂

    Grüssli



  • lord_fritte schrieb:

    Sobald ich beides in die selbe Datei packe läuft es ohne Fehler!!

    Also unter die Klasse, nicht innerhalb? Prüf doch, ob sich die Header im gleichen Verzeichnis befinden, und ob die Dateinamen überhaupt mit dem in #include angegebenen Namen übereinstimmen.



  • Nexus schrieb:

    lord_fritte schrieb:

    Sobald ich beides in die selbe Datei packe läuft es ohne Fehler!!

    Also unter die Klasse, nicht innerhalb? Prüf doch, ob sich die Header im gleichen Verzeichnis befinden, und ob die Dateinamen überhaupt mit dem in #include angegebenen Namen übereinstimmen.

    Ja unterhalb der Klasse, und ich habe alles geprüft, Dateien sind im selben Verzeichnis, Dateinamen sind korrekt.
    Aber getrennt in 2 Dateien = Fehler.
    Zusammen on einer Datei = Es läuft super.

    Aber wie gesagt, ich hatte das Problem schonmal und da hatte jemand erwähnt dass sich Klassen mit Templates nicht trennen lassen.


Anmelden zum Antworten