Template-Klasse, Template-Funktionen und friend-Deklaration



  • Hallo zusammen,
    ich versuche gerade für meine Prüfung einen Heapsort zu programmieren.
    Es funktioniert so lange bis ich die Klasse-Member als private deklariere, obwohl die zugreifenden globalen Methoden als friend deklariert sind.
    Warum? (ich bin mittlerweile sehr ratlos...)

    #ifndef HEAPSORT_H
    #define HEAPSORT_H
    
    #include<assert.h>
    #include<vector> 
    #include<iostream>
    
    typedef unsigned int uint;
    using namespace std;
    
    template<typename T>
    class Heapsort
    {
    
    private:	
    	vector<T> maxheap;
    	vector<T> sortiertes_v;
    
    public:
    	Heapsort(vector<T> const& v): sortiertes_v(), maxheap(v) {};
    
    	friend void gen_maxheap(vector<T>& v);
    	friend void test_sinken(vector<T>& v, uint i);
    	friend void sortieralgo(vector<T> const& v, Heapsort<T>& ergebnis);
    	inline void tausche(T& v, T& k);
    	inline void print(vector<T> const& v);
    	inline void print(Heapsort<T> const& v);
    
    };
    
    template<typename T>
    void gen_maxheap(vector<T>&  v)
    {
    	for(int i = (v.size() / 2 - 1) ; i >= 0; i--)
    	{
    		test_sinken( v, i);
    
    	}
    }
    template<typename T>
    void test_sinken(vector<T>& v, uint i)
    {
    	while(i <= v.size() / 2 - 1)
    	{
    		uint kindindex = 2*i + 1;			//Index des linken Kindknotens
    		if(kindindex+1 <= v.size()-1)			//Rechtes Kind?
    		{
    			if(v[kindindex] < v[kindindex+1])
    				kindindex++;
    		}
    
    		if(v[i] < v[kindindex])
    		{
    			tausche(v[i], v[kindindex]);
    			i = kindindex;
    		}
    		else
    			break;
    
    	}
    }
    
    template<typename T>
    void sortieralgo(vector<T>& v, Heapsort<T>& ergebnis)
    {
    	gen_maxheap<T>(ergebnis.maxheap);
    	vector<T> w= ergebnis.maxheap;
    
    	while(w.size() > 0)
    	{
    		tausche(w.front(), w.back());
    		(ergebnis.sortiertes_v).push_back(w.back());
    		w.pop_back();
    		if(w.size()==1)
    		{
    			(ergebnis.sortiertes_v).push_back(w.back());
    			w.pop_back();
    		}
    		else
    			test_sinken(w, 0);
    	}
    }
    
    template<typename T>
    	void tausche(T& v, T& k)
    	{
    		T temp = v;
    		v = k;
    		k = temp;
    	};
    
    template<typename T>
    void print(vector<T> const& v)
    {
    	for(uint i = 0; i < v.size(); i++)
    		{
    			cout << v[i] << " " ;
    		}
    		cout << endl;
    }
    
    template<typename T>
    void print(Heapsort<T> const& ergeb)
    {
    	print(ergeb.maxheap);
    	print(ergeb.sortiertes_v);
    }
    
    #endif
    

    error C2248: "Heapsort<T>::maxheap": Kein Zugriff auf private Member, dessen Deklaration in der Heapsort<T>-Klasse erfolgte.

    es kommen auch noch einige andere Fehlermeldungen, aber das ist zunächst denke ich das größte Problem...dass die Funktionen nicht auf die private Member zugreifen können.

    Hab Ihr einen Tipp für mich woran das liegt?

    Danke,
    Kathy



  • gcc sagt

    C:\irgendwo\main.cpp|22|warning: friend declaration 'void gen_maxheap(std::vector<T>&)' declares a non-template function|

    template<typename T>
    class Heapsort
    {
    
    private:	
    	vector<T> maxheap;
    	vector<T> sortiertes_v;
    
    public:
    	Heapsort(vector<T> const& v): sortiertes_v(), maxheap(v) {};
    
            template<typename U> friend void gen_maxheap(vector<U>& v);
    ...
    


  • aber wenn ich das ändere kommen die gleichen Fehlermeldungen immer noch...

    heapsort_klasse.h(69): error C2248: "Heapsort<T>::maxheap": Kein Zugriff auf private Member, dessen Deklaration in der Heapsort<T>-Klasse erfolgte.
    1> with
    1> [
    1> T=char
    1> ]

    das ist die erste...



  • Kathy88 schrieb:

    aber wenn ich das ändere kommen die gleichen Fehlermeldungen immer noch...

    heapsort_klasse.h(69): error C2248: "Heapsort<T>::maxheap": Kein Zugriff auf private Member, dessen Deklaration in der Heapsort<T>-Klasse erfolgte.
    1> with
    1> [
    1> T=char
    1> ]

    das ist die erste...

    Komisch. Aber ich konnte auch nicht so gut testen, weil ich keine main() zum testen hatte, und weil ich auch gar nicht verstanden hatte, was die Klasse da soll und die friend-Funktionen (besser static?) und ich war ganz durcheinander.



  • #include<cassert>
    #include<vector> 
    #include<iostream>
    #include "Heapsort_Klasse.h"
    
    using namespace std;
    
    typedef unsigned int uint;
    
    int main()
    {
    	vector<char> v;
    	v.push_back('H');
    	v.push_back('E');
    	v.push_back('A');
    	v.push_back('P');
    	v.push_back('S');
    	v.push_back('O');
    	v.push_back('R');
    	v.push_back('T');
    
    	Heapsort<char> ergebnis(v);
    	sortieralgo(v,ergebnis);		//Aufruf des sortieralgorithmus
    	print(v);
    	print(ergebnis);
    
    	system ("pause");
    	return 0;
    }
    

    Das ist die main dazu. Das Programm soll ein "Vorführprogramm" für die Prüfung sein, daher hab ich versucht so viele Dinge wie möglich zu "zeigen".
    man kann das ganze auch ohne klasse machen...läuft auch.

    Ich verstehe halt bloß nicht warum trotz friend die keinen Zugriff haben soll.



  • mal grad ne andere frage, du deklarierst da noch 3 methoden (tausche und 2x print)

    und unten definierst du diese, sofern ich das richtig sehe.
    aber du schreibst dort:

    template<typename T>
    void print(Heapsort<T> const& ergeb)
    {
        print(ergeb.maxheap);
        print(ergeb.sortiertes_v);
    }
    

    anstelle von

    template<typename T>
    void Heapsort<T>::print(Heapsort<T> const& ergeb)
    {
        print(ergeb.maxheap);
        print(ergeb.sortiertes_v);
    }
    

    ist das gewollt?
    weil das ist eigentlich auch ein fehler...



  • Einmal const vergessen (dadurch war der Freund eine andere als die, die es echt gab) und einmal friend (dadurch war die existierende print gar kein friend).

    #ifndef HEAPSORT_H
    #define HEAPSORT_H
    
    #include<assert.h>
    #include<vector>
    #include<iostream>
    
    typedef unsigned int uint;
    using namespace std;
    
    template<typename T>
    class Heapsort
    {
    
    private:
        vector<T> maxheap;
        vector<T> sortiertes_v;
    
    public:
        Heapsort(vector<T> const& v): sortiertes_v(), maxheap(v) {};
    
    //    template<typename U> friend void gen_maxheap(vector<U>& v);
    //    template<typename U> friend void test_sinken(vector<U>& v, uint i);
        template<typename U> friend void sortieralgo(vector<U> const& v, Heapsort<U>& ergebnis);
    //    template<typename U> inline void tausche(U& v, U& k);
    //    template<typename U> inline void print(vector<U> const& v);
        template<typename U> friend inline void print(Heapsort<U> const& v);
    
    };
    
    template<typename T>
    void gen_maxheap(vector<T>&  v)
    {
        for(int i = (v.size() / 2 - 1) ; i >= 0; i--)
        {
            test_sinken( v, i);
    
        }
    }
    template<typename T>
    void test_sinken(vector<T>& v, uint i)
    {
        while(i <= v.size() / 2 - 1)
        {
            uint kindindex = 2*i + 1;            //Index des linken Kindknotens
            if(kindindex+1 <= v.size()-1)            //Rechtes Kind?
            {
                if(v[kindindex] < v[kindindex+1])
                    kindindex++;
            }
    
            if(v[i] < v[kindindex])
            {
                tausche(v[i], v[kindindex]);
                i = kindindex;
            }
            else
                break;
    
        }
    }
    
    template<typename T>
    void sortieralgo(vector<T> const& v, Heapsort<T>& ergebnis)
    {
        gen_maxheap<T>(ergebnis.maxheap);
        vector<T> w= ergebnis.maxheap;
    
        while(w.size() > 0)
        {
            tausche(w.front(), w.back());
            (ergebnis.sortiertes_v).push_back(w.back());
            w.pop_back();
            if(w.size()==1)
            {
                (ergebnis.sortiertes_v).push_back(w.back());
                w.pop_back();
            }
            else
                test_sinken(w, 0);
        }
    }
    
    template<typename T>
    void tausche(T& v, T& k)
    {
        T temp = v;
        v = k;
        k = temp;
    };
    
    template<typename T>
    void print(vector<T> const& v)
    {
        for(uint i = 0; i < v.size(); i++)
        {
            cout << v[i] << " " ;
        }
        cout << endl;
    }
    
    template<typename T>
    void print(Heapsort<T> const& ergeb)
    {
        print(ergeb.maxheap);
        print(ergeb.sortiertes_v);
    }
    
    #endif
    
    #include<cassert>
    #include<vector>
    #include<iostream>
    //#include "Heapsort_Klasse.h"
    
    using namespace std;
    
    typedef unsigned int uint;
    
    int main()
    {
        vector<char> v;
        v.push_back('H');
        v.push_back('E');
        v.push_back('A');
        v.push_back('P');
        v.push_back('S');
        v.push_back('O');
        v.push_back('R');
        v.push_back('T');
    
        Heapsort<char> ergebnis(v);
        sortieralgo(v,ergebnis);        //Aufruf des sortieralgorithmus
        print(v);
        print(ergebnis);
    
    //    system ("pause");
        cin.get();
        return 0;
    }
    


  • lol?

    ich hab jetzt rumprobiert und gemacht und getan

    mittendrin kamst du mir zuvor
    hast quasi nichts verändert und es läuft alles!!!

    das einzige was du jetzt anders gemacht hast ist, dass du statt

    friend void sortieralgo(vector<T> const& v, Heapsort<T>& ergebnis);
    

    das hier geschreiben hast

    template<typename U> friend void sortieralgo(vector<U> const& v, Heapsort<U>& ergebnis);
    

    also das template mit namen anders gesetzt hast, oder sehe ich das falsch?
    (das gleiche analog mit der adneren funktion)



  • Ja, und bei

    inline void print(Heapsort<T> const& v);
    

    auch das friend dazugemacht.



  • Supi, vielen, vielen Dank!
    Es funktioniert. Hab die ganzen U's nur wieder in T' umgewandelt, damit es konsistent ist, oder hatte das einen speziellen Grund warum die in der Deklaration der Funktionen in der Klasse U statt T genommen hast?



  • Ich hätte da jetzt noch nen kleinen anderen Wunsch. Um die verschiedenen Möglichkeiten der Funktionsdefinition aufzuzeigen würde ich gerne die print-Funktion die ein Heapsort-Argument hat als Memberfunktion schreiben, also so:

    template<typename T> void print()
    	{
        print(maxheap);
        print(sortiertes_v);
    	}
    

    und rufe die dann auf mit:

    ergebnis.print();
    

    Dann bekomme ich aber die folgenden Fehler:

    error C2783: "void Heapsort<T>::print(void)": template-Argument für "T" konnte nicht hergeleitet werden.

    error C2780: 'void Heapsort<T>::print(const std::vector<T> &)': Erwartet 1 Argumente - 0 unterstützt

    Wo liegt mein Fehler in der Definition?



  • ja wenn man T für den klassen template parameter wählt und in dieser andere template funktionen (als friends) deklariert, muss das ja nicht heissen dass die parameter gleich oder verschieden sind.

    folglich sollte man den klassen parameter T(oder auch was belibiges anderes) nennen und die funktions templates innerhalb der klasse U. ob die definitionen auch diesen parameter haben ist eig egal...



  • Jetzt hast du dort eine Template-Funktion, bei der der Compiler mangels abhängiger Typen in der Parameter-Liste nicht entscheiden kann, für welches T er die Funktion generieren soll. In der Tat ist die Funktion aber auch unabhängig von T, wie es ausschaut.
    Ein Aufruf müsste zur Zeit so aussehen:

    ergebnis.print<int>();
    


  • Also du meinst ich könnte das template... weglassen?
    Mit dem Aufruf

    ergebnis.print<char>();
    

    geht es leider auch nicht.

    Hab noch überlegt ob ich dann in die Funktion void print() const

    print<T>(maxheap);
    print<T>(sortiertes_v);
    

    schreiben muss, aber auch das geht nicht.
    Da kommt dann:
    error C2662: 'void Heapsort<T>::print<T>(const std::vector<_Ty> &)': this-Zeiger kann nicht von 'const Heapsort<T>' in 'Heapsort<T> &' konvertiert werden



  • Was bedeutet "Es geht leider nicht" genau? Was sagt der Compiler dazu?



  • Also die Funktion sieht jetzt so aus:

    template<typename T> 
       void print()
      {
        print(maxheap);
        print(sortiertes_v);
      }
    

    und der Aufruf so:

    ergebnis.print<char>();
    

    dann sagt er:

    error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""public: void __thiscall Heapsort<char>::print<char>(class std::vector<char,class std::allocator<char> > const &)" (??print@D@?print@D@?Heapsort@D@@QAEXABV?vector@DV?vector@DV?allocator@D@std@@@std@@@Z)" in Funktion ""public: void __thiscall Heapsort<char>::print<char>(void)" (??print@D@?print@D@?Heapsort@D@@QAEXXZ)".

    und

    fatal error LNK1120: 1 nicht aufgelöste externe Verweise.



  • Naja, er findet jetzt keine Implementierung der print-Funktion, die ein "const std::vector<char>&" verlangt...

    Aber wie du schon sagtest, die template-Sache ist eigentlich völlig unnötig bei dieser Funktion. Alle Funktionen in einem Klassentemplate sind schon implizit von den Template-Parametern der Klasse abhängig, das heißt, solange die Funktion nicht noch von einem anderen Typ abhängen soll, kannst du dir eine template-Methode sparen.



  • Ok, wenn ich jetzt aber schreibe

    void print()
    {
        print(maxheap);
        print(sortiertes_v);
    }
    

    sagt der Compiler mir:

    error C2780: 'void Heapsort<T>::print(const std::vector<T> &)': Erwartet 1 Argumente - 0 unterstützt

    Was muss ich denn da jetzt noch verändert, dass der Aufruf funktioniert-



  • oder noch besser wäre:

    void print() const
    {
        print(maxheap);
        print(sortiertes_v);
    }
    

    aber da kommt auch wieder

    error C2780: 'void Heapsort<T>::print(const std::vector<T> &)': Erwartet 1 Argumente - 0 unterstützt
    1> with
    1> [
    1> T=char
    1> ]



  • Kannst du bitte deinen aktuellen Quelltext nochmal ganz posten? Ich weiß ja nicht, ob du die inkorrekte definition der Methoden außerhalb der Klasse inzwischen schon gefixt hast usw.

    Und irgendwie muss ich auch mal anmerken, dass mir die ganze Klasse mit ihren friend-Funktionen da ziemlich komisch und undurchsichtig anmutet!


Log in to reply