problem mit stack und basisklasse



  • hab ich doch in der LStack:

    T& top();

    oder wie meinst du das?



  • uhsuhz schrieb:

    ich schreib mal jetzt die 2 klassen, aber ohne funktionen

    Ups, da hab ich wohl nach deiner Mitteilung zu wenig genau hingeschaut. Dennoch hast du die Funktion nur deklariert, was dir noch gar nichts bringt 😉

    Definier die Funktion top() und versuch doch einfach mal, eine Referenz auf den ersten Wert zurückzugeben. Wenn ich dir den Code poste, bringt das uns beiden nichts. Bei konkreten Problemen kannst du ja wieder nachfragen.



  • ach so wir haben aneinander vorbeigeredet^^ ich habe gemeint nur die deklaration der funktionen, die aber schon alle implementiert sind:

    hier ist mal die ganze klasse:

    #ifndef LSTACK_H
    #define LSTACK_H
    
    #include "lcontainer.h"
    
    template<class T>
    class LStack :public LContainer<T>
    {
    public:
    	LStack();
    	LStack(const LStack& other);
    	~LStack();
    	void push(const T& v);
    	T pop();
    	T& top();
    	void swap(LStack& other);
    	LStack<T>& operator=(const LStack& other);
    };
    
    template<class T>LStack<T>::LStack()
    :LContainer<T>::LContainer()
    {
    }
    
    template<class T>LStack<T>::LStack(const LStack &other)
    :LContainer<T>::LContainer()
    {
    	if(!other.ptrtofirst) //leerer Stack, nichts zu kopieren
    		return;
    	this->ptrtofirst = new Element(other.ptrtofirst->data); //wenn hier was fliegt räumt C++ selber auf
    	Element *rigth = other.ptrtofirst;
    	Element *left = ptrtofirst;
    	while(rigth->next)
    	{
    		try
    		{
    			left->next = new Element(rigth->next->data); //sollte hier was fliegen...
    			rigth = rigth->next;
    			left = left->next;
    		}
    		catch(...)
    		{
    			clear();   //müssen wir selber aufräumen
    			throw;
    		}
    	}
    }
    
    template<class T>LStack<T>::~LStack()
    {
    	LContainer::~LContainer();
    }
    
    template<class T>void LStack<T>::push(const T& v)
    {
    	Element* temp = new Element(v);
    	temp->next = this->ptrtofirst;
    	this->ptrtofirst = temp;
    	++anz_elem;
    }
    
    template<class T>T LStack<T>::pop()
    {
    	if(!this->ptrtofirst)
    		throw EmptyLContainerException();
    	T result(this->ptrtofirst->data);
    	Element *temp = this->ptrtofirst;
    	this->ptrtofirst = this->ptrtofirst->next;
    	delete(temp);
    	--anz_elem;
    	return result;
    }
    
    template<class T>T& LStack<T>::top()
    {
    	if(!this->ptrtofirst)
    		throw EmptyLContainerException();
    	return this->ptrtofirst->data;
    }
    
    template<class T> void LStack<T>::swap(LStack &other)
    {
    	std::swap(this->anz_elem, other.anz_elem);
    	std::swap(this->ptrtofirst,other.ptrtofirst);
    }
    
    template<class T> LStack<T>& LStack<T>::operator=(const LStack& other)
    {
    	LStack<T> temp = other;
    	this->swap(temp);
    	return *this;
    }
    #endif
    


  • ich habe noch eine Frage:

    gibt es irgenteinen Sinn manche funktionen als konstantwährend zu deklarieren?

    Für mich gibt es keinen Sinn zB: einen const Stack zu erstellen, oder was meint ihr?



  • Die top() -Funktion sollte so eigentlich stimmen. Funktioniert sie? Und die restlichen Funktionen? Ich hab jetzt natürlich nicht deinen ganzen Code getestet. Aber schau mal, ob du keine Zugriffsverletzungen oder sonstige Fehler im Programm hast.

    Noch ein Detail: Es ist zwar Geschmackssache, aber du brauchst die this-> eigentlich nicht. Wenn sie dir bei der Übersichtlichkeit helfen, lass sie drin. Mich würden sie stören 😉

    uhsuhz schrieb:

    gibt es irgenteinen Sinn manche funktionen als konstantwährend zu deklarieren?

    Grundsätzlich schon. Erstens sieht man dann gerade (und stellt auch sicher), dass die Funktion die Klasse nicht verändert. Zweitens können wie gesagt auch konstante Instanzen diese Funktion benutzen.

    Zu dem gerade:

    uhsuhz schrieb:

    Für mich gibt es keinen Sinn zB: einen const Stack zu erstellen, oder was meint ihr?

    Nein, einen erstellen wohl kaum. Eher, wenn du bereits einen Stack hast, und von diesem eine konstante Kopie anfertigst. Oder wenn du eine konstante Referenz an eine Funktion übergibst.



  • ok danke, io die anderen funktionen funktionnieren alle, top klappt beim lesen auch schon mal hab noch nicht getestet, ob man auch schreiben kann.

    zum dem this. Ich weiß dass man es nicht braucht, aber ich mag es irgentwie lieber wenn ich this-> davor schreibe.

    nun habe ich noch ein frage, ich habe den == und den != operator in der basisklasse implementiert.

    template<class T>
    class LContainer
    {
    protected:
    	class Element
    	{
    	public:
    		T data;
    		Element* next;
    		Element(const T& v):data(v),next(NULL) {} //Copy C-tor von Element
    	};
    	class EmptyLContainerException: public std::exception
    	{
    		virtual const char* what() throw() {return "LContainer is empty";}
    	};
    	Element *ptrtofirst;
    	unsigned int anz_elem;
    public:
    	LContainer();
    	~LContainer();
    	unsigned int getAnzahlElement();
    	bool is_empty();
    	void clear();
    	bool operator==(LContainer& other);
    	bool operator!=(LContainer& other);
    };
    
    template<class T>bool LContainer<T>::operator ==(LContainer& other)
    {
    	if(this->anz_elem != other.anz_elem)
    		return false;
    	Element* rigth = other.ptrtofirst;
    	Element* left = this->ptrtofirst;
    	while(rigth)
    	{
    		if(rigth->data == left->data)
    		{
    			rigth = rigth->next;
    			left = left->next;
    		}
    		else
    			return false;
    	}
    	return true;
    }
    
    template<class T>bool LContainer<T>::operator!=(LContainer& other)
    {
    	if(*this == other)
    		return false;
    	return true;
    }
    

    ich dachte dass ich die funktionen überladen müsste in der LStack klasse, und dann per static_cast<LContainer<T>>(...) aufrufen müsste, aber irgenwie klappt es auch wenn ich den operator nicht überladen habe für die LStack-klasse, kann ich das so lassen, oder ist es sicherer wenn ich per static_cast gehe?



  • Wie kommt man auf die Idee vor seine Klassen so ein bescheuertes L zu setzen?



  • öhm vielleicht weil das L für Linked steht?
    aber dieser post war jetzt wirklick überflüssig, ich hätte die klasse ja auch
    HaltDieFresseStack nennen können, ist ja meine entscheidung



  • uhsuhz schrieb:

    ich dachte dass ich die funktionen überladen müsste in der LStack klasse, und dann per static_cast<LContainer<T>>(...) aufrufen müsste, aber irgenwie klappt es auch wenn ich den operator nicht überladen habe für die LStack-klasse, kann ich das so lassen, oder ist es sicherer wenn ich per static_cast gehe?

    Ich würde die Operatoren global machen und in den Klassen als Friend deklarieren. Ich würde dann aber für jeden Containertypen, der in der Praxis vorkommt, eine überladene Funktion definieren. Nach Möglichkeit lässt du die Implementierung für die Basisklasse weg, damit es nicht zu ungewollten Vergleichen (implizite Umwandlung) kommt. Oder du machst das ganze in der Klasse (evtl. polymorph). Aber lass op== für die Basisklasse weg, wenn er nicht gebraucht wird.

    Und den !=-Operator kannst du einfacher implementieren:

    template<class T>bool LContainer<T>::operator!=(LContainer& other)
    {
        return !(*this == other);
    }
    

    Und right schreibt man so 😉



  • Nexus schrieb:

    Und right schreibt man so 😉

    lol hab da wohl nicht aufgepasst^^ na lieber mal schnell ändern^^

    //Edit
    hmm irgentwie verstehe ich nicht genau was ich da machen soll...:-( also aus der basisklasse rausnehmen ist ja klar, aber dann haben die ja keinen zugriff mehr auf element?? und auch nicht mehr auf ptrtofirst, ich müsste die funktion höchstens als friend deklarieren,hmm da bräuchte ich vielleicht wenn es geht genauere beschreibungen 😞



  • Wenn du eine Klasse hast, und diese soll externen Funktionen Zugriff auf private Member gewähren, musst du diese Funktionen in der Klasse als Friend deklarieren.

    // Deklaration und Definition der Funktion (genauer: des überladenen Operators)
    bool operator==(const MyClass& Left, const MyClass& Right)
    {
        // ...
    }
    
    class MyClass
    {
        // Friend-Deklaration innerhalb der Klasse; operator== kann jetzt
        // auf private Member von MyClass zugreifen
        friend bool operator==(const MyClass& Left, const MyClass& Right);
    };
    


  • uhsuhz schrieb:

    öhm vielleicht weil das L für Linked steht?
    aber dieser post war jetzt wirklick überflüssig, ich hätte die klasse ja auch
    HaltDieFresseStack nennen können, ist ja meine entscheidung

    loooooooool



  • hmm ich merke gerade, dass ich deque gar nicht von basis ableiten kann, da next ja kein prev kennt... gibt es da eventuell eine möglichkeit, dass next aus der basisklasse prev kennt?



  • uhsuhz schrieb:

    hmm ich merke gerade, dass ich deque gar nicht von basis ableiten kann, da next ja kein prev kennt... gibt es da eventuell eine möglichkeit, dass next aus der basisklasse prev kennt?

    Ehm.. Du speicherst dir auch einen Verweise auf prev?! 🙄



  • @nexus ich habe es nun so gelöst, dass ich in der Containerklasse:

    template<class T>
    class MyContainer
    {
    	template<class T>friend bool operator==(const MyContainer& leftContainer,const MyContainer& rightContainer);
    .
    .
    .
    };
    

    und dann in der stack klasse noch mal:

    template<class T> bool operator==(const MyStack<T>& left,const MyStack<T>& right)
    {
    	return (static_cast<MyContainer<T>>(left) == static_cast<MyContainer<T>>(left));
    }
    
    template<class T> bool operator!=(const MyStack<T>& left,const MyStack<T>& right)
    {
    	return !(left == right);
    }
    

    diese funktionen sind aber nicht freunde der klasse, brauchen sie auch nicht. funktionieren tut es schon mal^^



  • Ableitung macht hier wenig Sinn. Was du willst ist Komposition.
    Damit loesen sich uebrigens auch alle Namensprobleme in Luft auf.

    Stack und Deque sind zwar Container, aber bei Vererbung das Liskov Substitution Principle beachten.



  • Shade Of Mine schrieb:

    Ableitung macht hier wenig Sinn. Was du willst ist Komposition.
    Damit loesen sich uebrigens auch alle Namensprobleme in Luft auf.

    Stack und Deque sind zwar Container, aber bei Vererbung das Liskov Substitution Principle beachten.

    io ich werde mir das morgen mal anschauen, für heute habe ich genug^^


Anmelden zum Antworten