Konstrukor mit Argumenten



  • Hey,

    ich bin von Delphi zu C++ gewechselt und habe ein kleines Problem durch den Wechsel. Ich habe eine Klasse, die beim Start des Programms erstellt wird. Das Erstellen hängt aber von einigen Faktoren ab, weshalb ich dem Konstruktor Argumente übergebe.

    TCivilization civi(100,100);
    

    Durch diese Argumente wird ein 2 Dimensionales Array mit 100 Breite und 100 Höhe erstellt. Das Problem ist aber, dass ich den Konstruktor des Objekts quasi erst später aufrufe und also sowas wie in Delphi

    civi: TCivilization
    
    procedure Irgendwas();
    begin
     civi := TCivilization.Create(x,y);
    end;
    

    schreiben kann. Ich bin leider absolut neu in C++ und habe keinen Ansatz. Ich hab es bis jetzt so gemacht:

    TCivilization *civi;
    void __fastcall TForm2::FormCreate(TObject *Sender)
    {
    	civi = new TCivilization(50,50);
    	civi->SetCell(1,8,alive);
    }
    

    Bekomm dann aber beim Start ne Zuriffsverletzung. Könnt ihr mir helfen?



  • Da du die Klassendefinition nicht mitgepostet hast hier folgendes sehr einfaches Beispiel:

    Konstruktor mit Parameter:

    //Klassendefinition:
    class MeineKlasse
    {
    public:
       MeineKlasse(int,int);
       ~MeineKlasse();
    
    private:
    int wert1;
    int wert2;   
    };
    
    //--------------------------
    
    //Konstruktor:
    MeineKlasse::MeineKlasse(int x, int z)
     : wert1(x),wert2(z)  //Initialisierung von Klassenmember
    {
       //evtl. weitere Initialisierungen oder Code der beim erstellen der Klasse ausgeführt werden soll.
    }
    
    //--------------------------
    //Destruktor:
    MeineKlasse::~MeineKlasse()
    {
       //aufräumen
    }
    
    //--------------------------
    
    //Neue Instanz auf dem heap Anlegen:
    MeineKlasse *neueklasseninstanz = new MeineKlasse(12,67); //Ruft Konstruktor der Klasse auf und initialisiert die vordefinierten Member und legt einen Zeiger
    der neuen Instanz im Pointer neueklasseninstanz ab.
    
    neueklasseninstanz->wert1 = 123;
    neueklasseninstanz->wert1 = 673;    //Zugriff bzw. Zuweisung der Klassenvariablen
    
    delete neueklasseninstanz;  //Ruft den Destruktor der neuen Instanz auf und gibt durch die Klasse MeineKlasse genutzten Speicher wieder frei.
    


  • Hey,

    danke erstmal, das hatte ich ja auch schon, das Problem ist, dass ich das Objekt global brauche. So wie du das geschrieben hast stehen diese Anweisungen doch dann in void's oder functions drinnen und haben dann nur einen begrenzten Gültigkeitsbereich oder?

    Mein Konstruktor der Klasse sieht so aus:

    TCivilization::TCivilization(int width, int height)
    {
    	//0=dead;1=alive;2=stays;3=invert;
    	neighbors[0] = 0; neighbors[1] = 0; neighbors[2] = 2; neighbors[3] = 1;
    	neighbors[4] = 0; neighbors[5] = 0; neighbors[6] = 0; neighbors[7] = 0;
    	neighbors[8] = 0;
    
    	maxPos.x = width - 1; maxPos.y = height - 1;
    
    	steps = 0;
    
    	field = new char *[width];
    	temp_field = new char *[width];
    
    	for (int x = 0  ; x < maxPos.x ; x++)
    	{
    		field[x] = new char [height];
    		temp_field[x] = new char [height];
    
    		for (int y = 0 ; y < maxPos.y ; y++)
    		{
    			field[x][y] = 0;
    			temp_field[x][y] = 0;
    		}
    	}
    
    }
    

    Was mich bei deinem Code gleich verwirrt und ehrlich gesagt generell bei C++ ist, dass du das Objekt erst als Zeiger deklarierst und dann nicht mit "." sondern "->" arbeitest. Wäre nett, wenn du näher darauf eingehen würdest. In Delphi nimmt man Zeiger halt nur, wenn man es wirklich braucht 😃



  • In C++ nimmt man Zeiger auch nur dann wenn man sie braucht. Wann immer möglich und sinnvoll werden eigentlich Referenzen verwendet.



  • Frolo schrieb:

    ...

    TCivilization::TCivilization(int width, int height)
    {
    	//0=dead;1=alive;2=stays;3=invert;
    	neighbors[0] = 0; neighbors[1] = 0; neighbors[2] = 2; neighbors[3] = 1;
    	neighbors[4] = 0; neighbors[5] = 0; neighbors[6] = 0; neighbors[7] = 0;
    	neighbors[8] = 0;
    
    	maxPos.x = width - 1; maxPos.y = height - 1;
    
    	steps = 0;
    
    	field = new char *[width];
    	temp_field = new char *[width];
    
    	for (int x = 0  ; x < maxPos.x ; x++)
    	{
    		field[x] = new char [height];
    		temp_field[x] = new char [height];
    
    		for (int y = 0 ; y < maxPos.y ; y++)
    		{
    			field[x][y] = 0;
    			temp_field[x][y] = 0;
    		}
    	}
    
    }
    

    Das ist wirklich übel und fehleranfällig. Du solltest dir überlegen, ob du das 2D Array nicht als eigene Klasse implementieren möchtest. Diskussionen und Anregungen gibt es hier im Forum zuhauf.
    Was soll deine TCivilization Klasse denn eigentlich können?



  • Ich bin von anderen Sprachen 2D Array halt gewöhnt und wollte das so weiter machen. Ich programmiere grad Cornway's Game Of Life und "field" ist halt mein Feld auf dem die einzelnen Punkte sind. Ich wüsste nicht nach was ich suchen sollte, weil ich schon lange damit verbracht habe das auf Pointern basierende Array hinzubekommen. Verbesserungen finde ich ja immer gut nur wie? Sobald ich irgendwas dynamisches haben will brauche ich doch immer Pointer und ist es da nicht egal, ob ich das 2D mach oder 2 * 1D?

    Also wie würdest du so eine Klasse realisieren? Abgeneigt bin ich nicht, weil mich das Pointer gefickel auch aufregt 🙂 Muss halt dynamisch sein 😃



  • Nein, du kommst völlig ohne Pointer aus, wenn du die STL die Arbeit erledigen lässt. Zur Realisierung eines 2D Arrays brauchst du lediglich einen Wrapper um ein 1D Array. Das 1D Array gibt´s schon fertig in der STL, heißt std::vector .

    Das könnte etwa so aussehen:

    #include <vector>
    
    class array2D
    {
       std::vector<int> Data_;
       unsigned int Rows_;
       unsigned int Cols_;
    
    public:
       array2D()
       {
          resize( 0,0 );
       }
    
       array2D( unsigned int Rows, unsigned int Cols )
       {
          resize( Rows, Cols );
       }
    
       void resize( unsigned int Rows, unsigned Cols )
       {
          Data_.resize( Rows * Cols );
          Rows_ = Rows;
          Cols_ = Cols;
       }
    
       int& operator()( unsigned int Row, unsigned int Col )
       {
          // ausgelassen: Range Check
          return Data_[Row * Cols_ + Col];
       }
    
       const int& operator()( unsigned int Row, unsigned int Col ) const
       {
          // ausgelassen: Range Check
          return Data_[Row * Cols_ + Col];
       }
    };
    
    int main()
    {
       array2D myArr( 4,5 ); // 4 Zeilen á 5 Spalten
       myArr( 2,3 ) = 5;     // Zuweisung an Zelle [2,3]
       int v = myArr( 2,3 ); // Abfrage von Zelle [2,3]
    }
    

    Das ist nur ein Ansatz, die Klasse könnte noch um einige Methoden erweitert oder als Template ausgelegt werden.

    + Kommt völlig ohne Zeiger aus
    + korrekt kopierbar
    + intuitiv bedienbar
    + keine manuelle Speicherverwaltung



  • Okay erstmal vielen Dank. Aber ich verstehe daran noch einiges nicht und mags deswegen nicht einfach übernehmen. Ist irgendwie was komplett Neues für mich o:

    int& operator()( unsigned int Row, unsigned int Col )
       {
          // ausgelassen: Range Check
          return Data_[Row * Cols_ + Col];
       }
    
       const int& operator()( unsigned int Row, unsigned int Col ) const
       {
          // ausgelassen: Range Check
          return Data_[Row * Cols_ + Col];
       }
    

    Davon verstehe ich eigentlich garnichts. Ich verstehe nicht warum da int& steht, ich verstehe auch nicht, warum da "operator()( .. )" steht und das mit dem "const" macht für mich auch keinen Sinn. Wäre also lieb, wenn du es für "Kleine" erklären könntest 🙂

    EDIT:// hab das angeschaut: http://www.c-plusplus.net/forum/232010-full Ich verstehs halbwegs, aber warum nur operator() und nicht operator=

    EDIT2:// habs verstanden thx. Echt genial, was man mit C++ für Möglichkeiten hat o:

    EDIT3:// Was hat das const zu bedeuten? Das versteh ich doch noch nicht 😞



  • Bezüglich Edit 3 lies mal das hier
    http://www.gia.rwth-aachen.de/Lehre/Cpp/script/online/node129.html
    Die const Version wird aufgerufen wenn du sie auf ein konstantes Objekt anwendest.

    void machWasFunktion(const array2D& arr) {
       int data = arr(1,1); // hier wird die konstante Version aufgerufen
    }
    

Log in to reply