Konstruktor



  • Hallo,
    ich mache gerade meine ersten Schritte mit C++ und habe eine Frage.
    Ich wollte mir eine KLasse schreiben, mit der ich eine Matrix und zwei Vektoren auspanne, um mit diesen zu rechnen. Die Matrix wird auch erfolgreich erzeugt, aber die Vektoren werden nicht erzeugt.

    #include <stdio.h>
    #include <stdlib.h>
    
    class Matrix {
    	double* matrixBag;
    	double* xBag;
    	double* yBag;
    private:
    	int maxcols;
    	int maxrows;
    public:
    	Matrix(int i, int j) {
    		matrixBag = (double*) malloc(sizeof(double)*i*j);
    		maxrows = i;
    		maxcols = j;
    	}
    	yVector(int i) {
    		yBag = (double*) malloc(sizeof(double)*i);
    	}
    	xVector(int i) {
    		xBag = (double*) malloc(sizeof(double)*i);
    	}
    
    	bool Jacobi() {
    		return true;
    	}
    };
    
    void main(void) {
    	Matrix dblMatrix = Matrix(3,3);
    	yVector y = yVector(3);
    }
    

    Ich vermute es hat etwas mit dem Konstruktor zu tun !?!? - Wie würde man das konventionell lösen?



  • Ich würde die Methoden xVector() und yVector() weglassen und deren Inhalt stattdessen in den Konstruktor mit reinpacken.

    (btw, in C++ nimmt man besser new/delete anstelle von malloc/free)



  • Kannst Du mir mal bitte zeigen wie das geht?

    Wenn möglich auch eine Variante ohne new/delete.

    Vielen Dank.

    P.S.: Wie erzeugt der Benutzer dann im Hauptprogramm diese beiden Vektoren? Der Programmierer\User soll merken, dass er gerade einen Vektor erzeugt hat.



  • Äh... Der Konstruktor der Klasse Matrix heisst Matrix, und nicht Matrix, xVector und yVector. xVector und yVector sind zwei (strenggenommen falsche, weil ohne Rückgabewert) Methoden.

    Klassen namens "xVector" und "yVector" gibt es hier garnicht, also kann man mit xVector x = xVector(3) auch kein Objekt davon erzeugen.

    Ich vermute Du willst eigentlich zwei Klassen schreiben 😉

    EDIT: Wenn ich nicht völlig merkbefreit bin "merke" ich eigentlich dass ich mit

    int i = 10;
    

    gerade ein Integer namens i angelegt habe 😉 *SCNR*



  • Matrix::Matrix(int i,int j)
    {
      matrixBag = new double[i*j]
      maxrows = i;maxcols = j;
      xBag = new double[i];
      yBag = new double[j];
    }
    

    (wenn du unbedingt willst, kannst du stattdessen auch malloc verwenden, aber ich würde es nicht empfehlen - besser wäre möglicherweise ein STL-Container anstelle der rohen Daten).

    P.S.: Wie erzeugt der Benutzer dann im Hauptprogramm diese beiden Vektoren? Der Programmierer\User soll merken, dass er gerade einen Vektor erzeugt hat.

    Die werden zusammen mit der Matrix erzeugt, wenn diese angelegt wird. Wenn du wirklich explizit einen neuen Vektor zuweisen willst, machst du das per Methoden-Aufruf:

    class Matrix
    {
    public:
      ...
      void setXVector(int i)
      { xBag=new double[i]; }
      void setYVector(int i)
      { yBag=new double[i]; }
      ...
    }
    
    int main()
    {
      Matrix m(3,3);
      m.setXVector(3);
    }
    


  • hallo,

    vielen dank für die Antwort - bin schon etwas weiter.
    Ich habe noch einige allgemeine Fragen. Vielleicht könnt Ihr mir auf die eine oder andere Antworten.

    #include <stdio.h>
    #include <stdlib.h>
    
    class solve {
    private:
    
    public:
    	int cols;
    	int rows;
    
    	double* AMatrix;
    	double* XVector;
    	double* YVector;
    
    	solve::solve(int i, int j) {
    		AMatrix = (double*) malloc(sizeof(double)*i*j);
    		XVector = (double*) malloc(sizeof(double)*i);
    		YVector = (double*) malloc(sizeof(double)*i);
    		rows = i;
    		cols = j;
    	}
    
    	solve::bool Jacobi() {
    		return true;
    	}
    };
    
    void main(void) {
    	solve matrixA(3,3);
    	//matrixA.AMatrix
    	//Matrix dbly = xVector(3,1);
    
    	printf("%d\n", matrixA.cols);
    }
    

    1. Wofür steht denn solve::solve ?? Wie würde man sinnvoll die Klasse benennen - Muss der Konstruktor gleich wie die Klasse heißen? Ich würde den Konstruktor gerne Init nennen der Klasse aber einen anderen Namen geben.
    2. Wie muss ich die Variablen rows und cols verändern, so dass diese von außerhalb nur lesbar sind? Wenn ich diese in den private-Bereich schreibe, kann ich sie auch nicht auslesen. Muss ich dafür extra Methoden erzeugen?
    3. Wie würdet Ihr am sinnvollsten einen Vektor (Zahlenwerte) an die Klasse übergeben - nicht gleich zu komplex zum Einstieg.

    Vielen Dank



  • 1. solve::solve ist Quatsch, so schreibst du es, wenn du den Konstruktor außerhalb der Klassendeklaration (alles zwischen class bla { und };) definierst. Innerhalb der Deklaration heißt sie einfach solve, und ja, Konstruktoren müssen immer denselben Namen haben wie die Klasse. Es hindert dich zwar niemand daran, einfach eine Init Methode aus einem Konstruktor aufzurufen, aber das ist hier ziemlich sinnlos.

    2. Ja.

    3. Wie wärs mit einer kleinen Vektor-Klasse (oder Struktur)?

    Solve hört sich so an, also sollte dieses Ding etwas tun. Das hieße, du bräuchtest eine Funktion, Matrix und Vektor sind dann Klassen (der Vektor kann auch als Matrix ausgedrückt werden), deren Objekte an Solve übergeben werden.



  • Wie meinst Du das zu 3.) ? (Übergabe der Vektoren, Matrizen. Ich muss sowohl einzelne Elemente als auch ein ganzes Feld übergeben oder wieder auslesen. Wäre toll, wenn Du mir noch einen Tip geben würdest)?

    Meine Klasse beherbergt eine Matrix und zwei Vektoren. A*x=y
    y und A werden durch den Anwender als Arumente übergeben, um das Gleichungssystem anschließend iterativ zu lösen (Aufruf von Jacobi).

    #include <stdio.h>
    #include <stdlib.h>
    
    class Lineqsys {
    private:
    	int cols;
    	int rows;
    public:
    	double* AMatrix;
    	double* XVector;
    	double* YVector;
    
    	Lineqsys(int i, int j) {
    		AMatrix = (double*) malloc(sizeof(double)*i*j);
    		XVector = (double*) malloc(sizeof(double)*i);
    		YVector = (double*) malloc(sizeof(double)*i);
    		rows = i;
    		cols = j;
    	}
    
    	Lineqsys::bool Jacobi(void) {
    		return true;
    	}
    
    	int getRows(void) {
    		return rows;
    	}
    };
    
    void main(void) {
    	Lineqsys obj1(3,3);
    
    	printf("%d\n", obj1.getRows());
    }
    


  • Fällt dir nicht selber auf, dass das logisch absolut nicht einleuchtend ist?
    Viel sinnvoller wäre doch sowas:

    class Matrix
    {
    // ...
    };
    
    class Vector
    {
    // ...
    };
    
    Vector solve_jacobi (const Matrix&, const Vector&)
    {
    // ...
    }
    
    int main ()
    {
        Matrix m = { { 2, 2 } , { 3, 3 } };
        Vector v = { 7, 3 };
    
        Vector r = solve (m, v);
        std::cout << r;
    }
    

    Noch ein bisschen grundsätzliches:
    1. In C++ verwendet man keine C-Header (z.B. stdio.h, stdlib.h). Für fast alles gibt es einen C++-Ersatz (für stdio.h iostream). Falls man doch mal einen solchen Header benötigt, benutzt man seine C++-Variante (stdio.h -> cstdio : stdlib.h -> cstdlib). Ein wichtiger Unterschied ist, dass die Funktionen dann im Namespace std stehen (s. std::cout).
    2. void main (void) ist Müll. Das erste void ist weder gültiges C noch C++ (dort muss int stehen), dass zweite void ist unnötig, da C++ für leere Klammern kein Argument erwartet.

    All das könntest du dir auch erlesen haben. Falls du ein Buch hast, schau dir nochmal den Bereich mit den Namensräumen an (dann wirst du auch den teils kryptisch anmutenden ::-Operator verstehen).



  • Hi,

    habe heute erst damit angefangen erste Schritte in C++ zu machen. Deshalb meine vielen Fragen.

    Du hast sicherlich recht - deine Struktur erscheint mir auch günstiger.

    Noch zwei letzte Frage:
    + Im Netz habe ich eine Methode gefunden, um einzelne Werte in das Array zu schreiben:

    class Matrix {
    private:
    	int cols;
    	int rows;
    
    	double* databag;
    public:	
    	// Konstruktor
    	Matrix(int i, int j) {
    		// Allokiere im Speicher für den Matrix-Vektor (AMatrix) und die Vektoren XVector, YVector
    		databag = (double*) malloc(sizeof(double)*i*j);
    	}
    
    	// Desktruktor
    	~Matrix {
    		free(databag);
    	}
    
    	double& operator()(int i, int j) const {
    		return databag[i*cols+j];
    	}
    }
    

    Aber wie definierst Du die Methode, mit der ein Feld/Array an Daten an die Vektoren übergeben werden.



  • Ich habe jetzt nicht ganz genau was Du letztlich vorhast, aber anbei eine Lösung, die ohne new/malloc auskommt. Die Methode 'Zeile' liefert Dir eine Zeile der matrix zurück.

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    class Matrix
    {
    public:
        Matrix( int zeilen, int spalten )
            : m_spalten( spalten )
            , m_databag( zeilen * spalten, 0.0 ) // mit 0'en vorbelegen
        {}
    
        double* operator[]( int iZeile ) // Zugriff auf eine Zeile; beginnend mit 0
        {
            return &m_databag[ m_spalten * iZeile ];
        }
        std::vector< double > Zeile( int iZeile ) const
        {
            const double* pZeile = &m_databag[ m_spalten * iZeile ];
            return std::vector< double >( pZeile, pZeile + m_spalten );
        }
    
    private:
        int m_spalten;
        std::vector< double > m_databag;
    };
    
    int main()
    {
        Matrix mx(4, 3);  // 4 Zeilen, 3 Spalten
        mx[0][0] = 1;  // erstes Element
        mx[2][1] = 34;
        mx[3][2] = -1; // letztes Element
    
        std::vector< double > zl = mx.Zeile( 2 );
        cout << "am Index 1 der zweiten Zeile steht: " << zl[1] << endl;
        return 0;
    }
    

    Gruß
    Werner


Anmelden zum Antworten