Frage zu einem Klassen-Template



  • Hallo zusammen nochmals eine Frage zu Template Klassen.

    Ich habe zwei Klassen, einmal Complex und einmal CMatrix. Diese waren vorher ohne Templates realisiert, ich möchte nun aber gerne für die Klasse Complex eine Template-Klasse anlegen.

    Das ist im Grunde ja nicht schwer, nur bekomme ich nun einen Error. Der Zeiger **dat vom Typ Complex fehlt nun die Argumentliste für "Klassenvorlage "Complex"". Auch bei der Speicherzuweisung das gleiche Problem.

    Welche Argumente müssen dem Zeiger denn übergeben werden und warum? In meinen Unterlagen wird auf so ein Problem nicht eingegangen 😕

    // Template Klasse Complex //
    template<typename T> class Complex
    {
    private:
    	T re;
    	T im;
    public:
    	Complex(T r=0, T i=0) : re(r), im(i) {}
    };
    
    // Alte Klasse Complex ohne Template //
    //class Complex
    //{
    //private:
    //	double re;
    //	double im;
    //
    //public:
    //	Complex(double r=0, double i=0) : re(r), im(i) {}
    //};
    
    class CMatrix
    {
    private:
    	Complex** dat; // Zeiger auf Zeiger auf Typ Complex mit Namen dat
    	int m; // Zeilen
    	int n; // Spalten
    
    public:
    	CMatrix (int n, int m);
    	~CMatrix();
    
    	int getM() const;
    	int getN() const;
    
    };
    
    CMatrix::CMatrix (int n, int m)
    	: m(m), n(n)
    {
    
    	dat = new Complex*[m]; // Speicher für Zeilen alokieren
    	for (int i=0; i<m; i++) // Speicher für Spalten alokieren
    		dat[i] = new Complex[n];
    
    }
    }
    

  • Mod

    Welche Art von Complex soll denn in der Matrix stehen? Complex<double>? Complex<int>? Complex<T>?

    Diese Information fehlt, die musst du angeben.

    In deinen Klassen sind mehrere dicke Designfehler:
    - Es gibt std::complex
    - Die Matrixklasse verwaltet ihren Speicher manuell, anstatt std::vector zu nutzen
    - Sieht tut dies auch noch falsch. Eben darum benutzt man std::vector.
    - Die Matrixklasse legt Listen von Listen an, was viel allgemeiner ist, als hier gewünscht. Die Matrix hat doch immer gleich lange Zeilen, also legt man alles in einem einzigen Block an und rechnet dann die Indizes passend. Das bringt einen wahnsinnigen Performancegewinn.

    edit: Tyle, du schon wieder? Wieso muss man dir in praktisch jedem Thread neu erklären, dass du std::vector nutzen sollst? Du machst immer wieder die gleichen Fehler!



  • Ok wenn ich caste (heisst das hier dann auch so) geht es, allerdings ist "T" ja nicht in der CMatrix bekannt. Gibt es da die Möglichkeit auch dort den allgemeinen Typ T zu nutzen, das die Class auch mit verschiedenen Datentypen ausgeprägt werden kann?
    Edit: Dort dann auch einfach ein Template definieren? Würde ich spontan so machen. Was aber vermutlich zu Fehlern führen würde...

    Ja den Namen habe ich mir nicht ausgedacht, rate mal... genau war ne Vorgabe 🙄

    Auch das selbe wieder mit Vektor, ist als Vorgabe nicht eingebunden... wie immer, geht wohl wieder darum den Speicher von Hand zu zu weisen. Ansonsten wäre Vektor hier natürlich wesentlich effektiver, muss man sich nicht drum kümmern... darum auch immer wieder die Erklärung zum Vektor 😞 sag das lieber meinem Prof...

    Für die Speicherzuweisung habe ich mich an die hier im Forum beschriebene Methode orrientiert: http://www.c-plusplus.net/forum/39489-full



  • Du kannst aus der Matrix auch ein template machen:

    template<class T>
    class Complex
    {
    // ...
    };
    
    template<class T>
    class CMatrix
    {
    // ...
        typename Complex<T>** dat;
    // ...
    };
    

    (Bin mir mit dem typename nicht sicher, müsste aber dahin, weil der Typ von einem template Parameter indirekt abhängt, oder?!)

    Aber Tyle, du willst trotzdem verschachtelte Arrays machen, auf eigene Faust. Beherzige SeppJ's Tipp und nimm nur ein Array und rechne dir die Indizes passend. (Hör ruhig auf den, der hat schon fast ~19000 Posts ;))



  • SeppJ hat schon gehörig Ahnung und auch fast immer recht mit dem was er sagt. Das Problem ist nur das ich meist gewisse Vorgaben bekomme, die man normalerweise in der Realität nicht benutzen würde, weil es viel zu umständlich wäre und nicht performant genug.

    In meinem Beispiel wurde in der CMatrix

    Complex **dat
    

    vorgegeben. Das entspricht halt gut der erklärent Methode hier: http://www.c-plusplus.net/forum/39489-full (Fall 1).


  • Mod

    Dann aber bitte wenigstens unter Beachtung der großen Drei, sonst geht das bei der ersten Kopie einer Matrix schief:
    http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)



  • Skym0sh0 schrieb:

    (Bin mir mit dem typename nicht sicher, müsste aber dahin, weil der Typ von einem template Parameter indirekt abhängt, oder?!)

    Nee, typename muss nicht.
    typename nur, wenn du auf ein typedef von etwas zugreifen willst, was von einem Template abhängig ist.



  • Tyle schrieb:

    CMatrix::CMatrix (int n, int m)
    	: m(m), n(n)
    {
    
    	dat = new Complex*[m]; // Speicher für Zeilen alokieren
    

    Mir ist kein Fall bekannt, wo eine Matrix als Matrix(Spalten,Zeilen) deklariert ist. Üblich wäre Matrix(Zeilen,Spalten).

    Skym0sh0 schrieb:

    Du kannst aus der Matrix auch ein template machen:

    template<class T>
    class Complex
    {
    // ...
    };
    
    template<class T>
    class CMatrix
    {
    // ...
        typename Complex<T>** dat;
    // ...
    };
    

    flexibler wäre:

    template<class T>
    class Complex
    {
    // ...
    };
    
    template<class T>
    class CMatrix
    {
    // ...
        T** dat; // besser T* dat und nur einen Datenbereich (hör' auf SeppJ)
          // und noch besser wäre eine eigene Buffer-Klasse, wenn Du std::vector<> nicht benutzen sollst
    // ...
    };
    
    typedef CMatrix<Complex<double> > CMatrixComplexDouble;
    

  • Mod

    Kenner der Matrix schrieb:

    // und noch besser wäre eine eigene Buffer-Klasse, wenn Du std::vector<> nicht benutzen sollst
    

    Da der Lehrer das anscheinend öfters macht, wäre das eigentlich mal eine sehr lohnende Investition. In 20-30 Minuten könnte man einen einfachen vector mit minimalem Interface (operator[]) programmieren. In 2-3 Stunden auch mit Iteratoren und den meistgenutzten Teilen der STL-Schnittstelle. Dadurch gewinnt man bei jeder weiteren Hausaufgabe extrem Komfort und Fehlerfreiheit, damit auch automatisch viel Zeit. Das Wiederbenutzen von oft benutztem Code ist gerade eines der Ziele einer Hochsprache und hier bietet sich das ganz besonders gut an.

    Für den unerfahrenen Threadersteller werden es wohl eher 2-3 Tage Programmierarbeit, aber dafür wird er ordentlich was dabei lernen. Wohl mehr als bei den hier gezeigten Übungsaufgaben.


Log in to reply