Matrix-Klasse



  • C weg vor dem Klassennamen und englische namen nutzen 🤡

    warum hat die methode SetzeWert einen bool return-value?



  • @davie: Danke für deine Vorschläge, werde mich drüber machen :).

    @ret: Ok, bool kommt weg ;). Mache ab demnächst bzw. fange z.Zt. mit nem Art Praktikum an (kein wirkliches, mehr so ne Mischung aus... naja egal :p) und dort werden allgemein deutsche Variablennamen benutzt, naja wie auch immer... versuche mich da halt bisschen anzupassen 🤡

    btw: Ist nur der Anfang ;O



  • Wenn du statt T** einen std::vector<T> der Größe spalten*zeilen verwendest, hast du keine Probleme mit Exceptionsicherheit, kannst dir den Destruktor sparen und hast einen automatisch generierten, korrekten Kopierkonstruktor und Zuweisungsoperator. Außerdem wird die Klasse (würde ich zumindest mal vermuten) sogar schneller und kleiner, weil die doppelte Indirektion unnötig viel Speicherverwaltungsoverhead bedingt, aber das ist eher ein netter Nebeneffekt. Das Indizieren wird dann zu m_DatenVektor[y * spalten + x].

    Die meisten Parameter für Dimensionen und Positionen könnten besser unsigned sein.

    Der protected-Teil gehört private. Ableiten ist eh gefährlich, weil CMatrix keinen virtuellen Destruktor hat, aber eh nicht sinnvoll: Wer die Klasse erweitern will, kann Nicht-Elementfunktionen dafür verwenden.



  • @operator void:

    Danke, klar das mit dem private ist auch irgendwie logisch, wollte eh eigentlich nichts von der Klasse ableiten. Ginge das Ganze vielleicht auch über zweidimensionale Vektoren (hab allerdings auch keine Ahnung wie man sowas deklariert bzw. damit umgeht)?

    Weiterhin danke für Eure Hilfe :).



  • Jup, du könntest vector<vector<T> > nehmen, das wäre dann näher an deiner Originalversion dran. Dann würde der Konstruktor so aussehen:

    // m_Daten ist vector<vector<T> >
    m_Daten.resize(zeilen);
    for (unsigned i = 0; i < zeilen; ++i)
    {
        m_Daten[i].resize(spalten);
    }
    

    Zugreifen könntest du dann auch über m_Daten[zeile][spalte].



  • Ok danke... Ist das nun so ok?

    template<class T>
    class Matrix
    {
    	public:
    		Matrix(int, int);
    		~Matrix();
    
    		T& LeseWert(int, int) const;
    		void SetzeWert(int, int, const T&);
    
    	private:
    		const unsigned int m_AnzahlZeilen, m_AnzahlSpalten;
    		std::vector<std::vector<T> > m_DatenVektor;
    };
    
    template<class T> Matrix<T> :: Matrix(int AnzahlZeilen, int AnzahlSpalten) :
    	m_AnzahlZeilen(AnzahlZeilen),
    	m_AnzahlSpalten(AnzahlSpalten)
    {
    	m_DatenVektor.resize(m_AnzahlZeilen);
    
    	for (unsigned int i = 0; i < m_AnzahlZeilen; ++i) 
    	{ 
    		m_DatenVektor[i].resize(m_AnzahlSpalten); 
    	}
    }
    
    template<class T> Matrix<T> :: ~Matrix()
    {
    	// ...
    }
    
    template<class T> T& Matrix<T> :: LeseWert(int Zeile, int Spalte) const
    {
    	return static_cast<T>(m_DatenVektor[Zeile][Spalte]);
    }
    
    template<class T> void Matrix<T> :: SetzeWert(int Zeile, int Spalte, const T &Wert)
    {
    	m_DatenVektor[Zeile][Spalte] = Wert;
    }
    

    MfG



  • Wenn die interne Repräsentation schon unsigned int verwendet, könnten die ganzen Parameter das auch tun.

    Wozu braucht die Klasse einen Destruktor?

    Dadurch, dass m_AnzahlZeilen und m_AnzahlSpalten "const" sind, kann der operator= nicht automatisch generiert werden.
    Zumindest eine der beiden Variablen kannst du auch leicht sparen, indem du einfach m_DatenVektor.size() verwendest.

    Die Zeile mit dem static_cast sieht komisch aus. Wenn du eine Lese- und eine Setze-Funktion hast, dann sollte die Lese-Funktion entweder const T& oder T zurückgeben, aber nicht T&. Wenn du schreiben können willst "Matrix.LeseWert(a, b) = 5", brauchst du dann noch einen zweiten Overload "T& LeseWert(int, int)", also ohne const. Einen Cast brauchst du in keinem Fall.



  • operator void schrieb:

    Jup, du könntest vector<vector<T> > nehmen, das wäre dann näher an deiner Originalversion dran. Dann würde der Konstruktor so aussehen:

    // m_Daten ist vector<vector<T> >
    m_Daten.resize(zeilen);
    for (unsigned i = 0; i < zeilen; ++i)
    {
        m_Daten[i].resize(spalten);
    }
    

    Zugreifen könntest du dann auch über m_Daten[zeile][spalte].

    Kürzer:

    m_Daten.resize(zeilen, vector<T>(spalten));
    

    wenn ich mich nicht irre.

    MfG Jester



  • Aus komplizierteren Gründen dürfte man sogar schreiben:

    : m_DatenArray(SpaltenAnzahl, ZeilenAnzahl)
    {
    }
    

    Aber deine Variante ist vermutlich am schönsten 🙂



  • Wird immer knapper :). Jetzt ok 🙄?

    typedef unsigned int uint;
    
    template<class T>
    class Matrix
    {
    	public:
    		Matrix(uint, uint);
    
    		T& LeseWert(uint, uint) const;
    		void SetzeWert(uint, uint, const T&);
    
    	private:
    		uint m_AnzahlZeilen, m_AnzahlSpalten;
    		std::vector<std::vector<T> > m_DatenVektor;
    };
    
    template<class T> Matrix<T> :: Matrix(uint AnzahlZeilen, uint AnzahlSpalten) :
    	m_AnzahlZeilen(AnzahlZeilen),
    	m_AnzahlSpalten(AnzahlSpalten)
    {
    	m_DatenVektor.resize(m_AnzahlZeilen, std::vector<T>(m_AnzahlSpalten));
    }
    
    template<class T> T& Matrix<T> :: LeseWert(uint Zeile, uint Spalte) const
    {
    	return static_cast<T>(m_DatenVektor[Zeile][Spalte]);
    }
    
    template<class T> void Matrix<T> :: SetzeWert(uint Zeile, uint Spalte, const T &Wert)
    {
    	m_DatenVektor[Zeile][Spalte] = Wert;
    }
    

    MfG


Anmelden zum Antworten