stack als klassen-template - probleme



  • hy!
    also ich habe vor einen stack als klassen-template umzusetzen (besser gesagt mein prof will das 😉 )
    ist mein erster versuch an templates, nur irgendwie will mein compiler mir das ganze nicht übersetzen. er bringt auch nur wirre fehlermeldungen, die mir nicht helfen auf die spur des problems zu kommen. ich denke für euch wird das problem wahrscheinlich auf den ersten blick erkennbar sein 😃 ...

    // Stack.h //
    
    #ifndef STACK_H_
    #define STACK_H_
    
    template<class ANY_TYPE>
    class Stack {
    public:
    	Stack(void);
    	~Stack(void);
    	bool push(const ANY_TYPE &);
    	bool top(ANY_TYPE &);
    	bool pop(void);
    	bool is_empty(void);
    private:
    	ANY_TYPE *stack_pointer;
    	int count;
    };
    
    #endif // STACK_H_
    
    // Stack.cpp //
    
    #include "Stack.h"
    
    template <class ANY_TYPE>
    Stack<ANY_TYPE>::Stack(void) {
    	stack_pointer = NULL;
    	count = 0;
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::push(const ANY_TYPE &element) {
    	stack_pointer[count] = new ANY_TYPE;
    	if(!stack_pointer[count])			// falls Heapspeichervoll
    		return false;
    	else {
    		stack_pointer[count] = element;
    		stack_pointer[++count] = NULL;
    		return true;
    	}
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::top(ANY_TYPE &element) {	// liest erstes element
    	if(is_empty())
    		return false;
    	else {
    		element = stack_pointer[--count];	// gibt erstes element zurueck
    		count++;
    		return true;
    	}
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::pop(void) {				// loescht erstes element
    	if(is_empty())
    		return false;
    	else {
    		delete stack_pointer[--count];
    		stack_pointer[count] = NULL;	// wird geloescht und dann NULL gesetzt
    		return true;
    	}
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::is_empty(void) {
    	if(stack_pointer[0] == NULL)	// prueft ob erstes element vorhanden
    		return true;
    	else
    		return false;
    }
    
    template <class ANY_TYPE>
    Stack<ANY_TYPE>::~Stack(void) {
    	int i;
    	for(i = count - 1; i <= 0; i--)
    		delete stack_pointer[i];
    }
    
    // stacktest.cpp //
    
    #include <iostream>
    #include "Stack.h"
    using namespace std;
    
    int main(void) {
    	float test;
    
    	cout << "stack mit templates" << endl;
    
    	Stack<float> *float_stack;
    	float_stack = new Stack<float>();
    	float_stack->push(3.1415);
    	float_stack->push(2.322);
    	float_stack->push(1.333);
    	float_stack->top(test);
    
    	cout << "1.333: ... " << test << endl;
    
    	return 0;
    }
    

    der compiler spuckt immer folgendes aus:

    ------ Erstellen gestartet: Projekt: uebung_07_templates, Konfiguration: Debug Win32 ------
    Kompilieren...
    main.cpp
    c:\eigene dateien\docs\fh\it4\informatik 3\uebungen\uebung_07_templates\uebung_07_templates\main.cpp(20) : warning C4700: Die nicht initialisierte lokale Variable "test" wurde verwendet.
    Verknüpfen...
    main.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: bool __thiscall Stack<float>::is_empty(void)" (?is_empty@?Stack@M@@QAE\_NXZ)" in Funktion "_main". main.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: \_\_thiscall Stack::Stack(void)" (??0?Stack@M@@QAE@XZ)" in Funktion "_main".
    C:\Eigene Dateien\docs\fh\it4\informatik 3\uebungen\uebung_07_templates\Debug\uebung_07_templates.exe : fatal error LNK1120: 2 nicht aufgelöste externe Verweise.
    Das Buildprotokoll wurde unter "file://c:\Eigene Dateien\docs\fh\it4\informatik 3\uebungen\uebung_07_templates\uebung_07_templates\Debug\BuildLog.htm" gespeichert.
    uebung_07_templates - 3 Fehler, 1 Warnung(en)
    ========== Erstellen: 0 erfolgreich, Fehler bei 1, 0 aktuell, 0 übersprungen ==========

    Würde mich freuen, wenn ihr kurz drüberrutschen könntet 😉



  • Die Implementierung _muss_ im Header stehen sonst klappts nicht.



  • was? die ganze Stack.ccp muss ich KOMPLETT in den header rein?

    also hab die Stack.cpp geloescht und habe nur noch folgende Stack.h

    // Stack.h // uebung 07 templates // wolfgang franz // 906787
    
    #ifndef STACK_H_
    #define STACK_H_
    
    template<class ANY_TYPE>
    class Stack {
    public:
    	Stack(void);
    	~Stack(void);
    	bool push(const ANY_TYPE &);
    	bool top(ANY_TYPE &);
    	bool pop(void);
    	bool is_empty(void);
    private:
    	ANY_TYPE *stack_pointer;
    	int count;
    };
    
    template <class ANY_TYPE>
    Stack<ANY_TYPE>::Stack(void) {
    	stack_pointer = NULL;
    	count = 0;
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::push(const ANY_TYPE &element) {
    	stack_pointer[count] = new ANY_TYPE;
    	if(!stack_pointer[count])			// falls Heapspeichervoll
    		return false;
    	else {
    		stack_pointer[count] = element;
    		stack_pointer[++count] = NULL;
    		return true;
    	}
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::top(ANY_TYPE &element) {	// liest erstes element
    	if(is_empty())
    		return false;
    	else {
    		element = stack_pointer[--count];	// gibt erstes element zurueck
    		count++;
    		return true;
    	}
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::pop(void) {				// loescht erstes element
    	if(is_empty())
    		return false;
    	else {
    		delete stack_pointer[--count];
    		stack_pointer[count] = NULL;	// wird geloescht und dann NULL gesetzt
    		return true;
    	}
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::is_empty(void) {
    	if(stack_pointer[0] == NULL)	// prueft ob erstes element vorhanden
    		return true;
    	else
    		return false;
    }
    
    template <class ANY_TYPE>
    Stack<ANY_TYPE>::~Stack(void) {
    	int i;
    	for(i = count - 1; i <= 0; i--)
    		delete stack_pointer[i];
    }
    
    #endif // STACK_H_
    

    ... motzt mich der compiler immernoch an:

    ------ Erstellen gestartet: Projekt: uebung_07_templates, Konfiguration: Debug Win32 ------
    Kompilieren...
    Stack.cpp
    Code wird generiert...
    Kompilieren...
    main.cpp
    c:\eigene dateien\docs\fh\it4\informatik 3\uebungen\uebung_07_templates\uebung_07_templates\main.cpp(14) : warning C4305: 'Argument': Verkürzung von 'double' in 'const float'
    c:\eigene dateien\docs\fh\it4\informatik 3\uebungen\uebung_07_templates\uebung_07_templates\main.cpp(15) : warning C4305: 'Argument': Verkürzung von 'double' in 'const float'
    c:\eigene dateien\docs\fh\it4\informatik 3\uebungen\uebung_07_templates\uebung_07_templates\main.cpp(16) : warning C4305: 'Argument': Verkürzung von 'double' in 'const float'
    c:\eigene dateien\docs\fh\it4\informatik 3\uebungen\uebung_07_templates\uebung_07_templates\stack.h(29) : error C2440: '=': 'float *' kann nicht in 'float' konvertiert werden
    Es gibt keinen Kontext, in dem diese Konvertierung möglich ist
    c:\eigene dateien\docs\fh\it4\informatik 3\uebungen\uebung_07_templates\uebung_07_templates\stack.h(28): Bei der Kompilierung der Klassen-template der bool Stack<ANY_TYPE>::push(const ANY_TYPE &)-Memberfunktion
    with
    [
    ANY_TYPE=float
    ]
    c:\eigene dateien\docs\fh\it4\informatik 3\uebungen\uebung_07_templates\uebung_07_templates\main.cpp(13): Siehe Verweis auf die Instanziierung der gerade kompilierten Klassen-template "Stack<ANY_TYPE>".
    with
    [
    ANY_TYPE=float
    ]
    Code wird generiert...
    Das Buildprotokoll wurde unter "file://c:\Eigene Dateien\docs\fh\it4\informatik 3\uebungen\uebung_07_templates\uebung_07_templates\Debug\BuildLog.htm" gespeichert.
    uebung_07_templates - 1 Fehler, 3 Warnung(en)
    ========== Erstellen: 0 erfolgreich, Fehler bei 1, 0 aktuell, 0 übersprungen ==========



  • Edit:
    Da ist noch ein Fehler in deinem code:

    ANY_TYPE *stack_pointer;
    ...
        stack_pointer[count] = new ANY_TYPE;
    

    1. damit das klappt, müsste der stack_pointer vom Typ ANY_TYPE ** sein (2 sterne).
    2. du hast kein speicher für den pointer angefordert. der zugriff mit dem index gibt garantiert einen zugriffsfehler.

    ich vermute, dass du die stl nicht verwenden darfst. dann musst du eine verkettete liste nehmen:

    // in der klasse (private)
    struct node
    {
        ANY_TYPE data;
        node *next;
    };
    //
    //
    // push :
    node *temp = new node;
    temp->data = element;
    temp->next = stack_pointer;
    stackpointer = temp;
    //
    //
    // top :
    if (stack_pointer)
        element = stack_pointer->data;
    else
        // fehler
    //
    //
    // pop :
    node *temp = stack_pointer;
    stack_pointer = stack_pointer->next;
    delete temp;
    //
    //
    //
    

    habs nicht getestet müsste aber klappen so



  • okay, hab den stack_pointer nun als ANY_TYPE = **stack_pointer; initialisiert. hatte ich auch bereits am anfang, aber ich dachte vllt liegt da das problem.

    oder bin ich jetzt vollkommen aufm falschen dampfer?! 😕



  • Damit erfüllst Du aber nich die folgende Anforderung:

    ex.aveal schrieb:

    ich soll das ganze als verkettete liste lösen

    Schau Dir am besten nochmal im Datenstrukturen-Skript den Unterschied zwischen einem Feld (Array) und einer (einfach/doppelt) verketteten Liste an 🙂



  • LordJaxom schrieb:

    Damit erfüllst Du aber nich die folgende Anforderung:

    ex.aveal schrieb:

    ich soll das ganze als verkettete liste lösen

    Schau Dir am besten nochmal im Datenstrukturen-Skript den Unterschied zwischen einem Feld (Array) und einer (einfach/doppelt) verketteten Liste an 🙂

    okay, ja, mir wirds jetzt langsam klar. ich hab mich da so reingesteigert, dass ich garnich mehr genau drauf geachtet hab, wies in der aufgabenstellung steht. dachte nur noch an liste, irgendne liste.

    mach das ganze jetzt über die structure, mal schaun ob ichs hinbekomm.
    mich würde aber trotzdem tierisch interessieren, wie ich es denn jetzt in meinem beispiel machen müßte.
    müßte ich ...

    ANY_TYPE **stack_pointer = new ANY_TYPE[100];
    

    (100 halt einfach mal als größe des Stacks)

    aber dann funzt es irgendwie auch nicht. ich hoffe ihr wisst was ich meine, denn ich bin selber schon total verwirrt 😃



  • nein, ANY_TYPE** ist nicht richtig man könnte es zwar mit einem doppelpointer machen aber das wäre noch aufwändiger abgesehen davon das es nichts bringt.

    eine verkettete liste sieht ungefähr so aus:

    stack_pointer ---> |-------|        |-------|
                        | daten |   |--> | daten |   |-->  hier kommt   --> NULL
                        | next  | --|    | next  | --|     noch was..
                        |-------|        |-------|
    

    um diese liste zu realisieren, brauchst du eine struktur um die daten und den
    Verweis auf das nächste element zusammenzuhalten.

    (empfehle http://de.wikipedia.org/wiki/Liste_(Datenstruktur))

    ich schreibe dir die klasse kurz um:

    template<class ANY_TYPE>
    class Stack
    {
    public:
        Stack(void);
        ~Stack(void);
        bool push(const ANY_TYPE &);
        bool top(ANY_TYPE &);
        bool pop(void);
        bool is_empty(void);
    private:
        ANY_TYPE *stack_pointer;
        int count;
        struct node
        {
            ANY_TYPE daten;
            node *next;
        };
    };
    
    template <class ANY_TYPE>
    Stack<ANY_TYPE>::Stack(void)
    {
        stack_pointer = NULL;
        count = 0;
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::push(const ANY_TYPE &element)
    {
        node *temp = new ANY_TYPE;
        if(!temp)            // falls Heapspeichervoll
            return false;
        else
        {
            temp->daten = element;
            temp->next = stack_pointer;
            stack_pointer = temp;
            return true;
        }
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::top(ANY_TYPE &element)
    {    // liest erstes element
        if(is_empty())
            return false;
        else
        {
            element = stack_pointer->daten;    // gibt erstes element zurueck
            return true;
        }
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::pop(void)
    {                // loescht erstes element
        if(is_empty())
            return false;
        else
        {
            node *temp = stack_pointer;
            stack_pointer = stack_pointer->next;    // wird geloescht und dann NULL gesetzt
            delete temp;
            return true;
        }
    }
    
    template <class ANY_TYPE>
    bool Stack<ANY_TYPE>::is_empty(void)
    {
        return stack_pointer ? false : true;    // prueft ob erstes element vorhanden
    }
    
    template <class ANY_TYPE>
    Stack<ANY_TYPE>::~Stack(void)
    {
        while (stack_pointer)
        {
            node *temp = stack_pointer;
            stack_pointer = stack_pointer->next;
            delete temp;
        }
    }
    

    das muss jetzt aber funktionieren

    mfg templater



  • ex.aveal schrieb:

    was? die ganze Stack.ccp muss ich KOMPLETT in den header rein?

    Nur als Erklärung, da ich die vermisse oder Übersehen habe:

    Templates müssen komplett bekannt sein, daher muss der Code entweder komplett im Header stehen (das übliche), oder als ein Ausnahmefall am ende des Headers die cpp inkludiert werden (Die man dann aber meist anders nennt wie z.b. .tmpl oder tcc...). Und die letzte Alternative (von kaum einen Compiler unterstützt, ich kenne nur den Comeau der das macht, habe auch schon gehört das inzwischen ein weiterer das können soll) gibt es noch export bei Templates - wegen der fehlenden Unterstützung aber in der Regel Unsinn.

    ex.aveal schrieb:

    uebung_07_templates - 1 Fehler, 3 Warnung(en)

    Grundsätzlich magst du mit den Warnungen leben, aber häufig deuten diese auch Probleme an (man sollte immer versuchen auch alle Warnungen zu beheben). Und Grundsätzlich sollte man es sich auch angewöhnen mit der höchsten Warnstufe zu arbeiten die vom Compiler unterstüzt wird (Wenn es aus externen Headern kommt gibt es meist Möglichkeiten diese zu unterdrücken, aber das sollte gezielt und mit Nachdenken erfolgen).

    cu André



  • habs jetzt, danke leudz!!!!!

    vielen dank an alle 🙂


Anmelden zum Antworten