Konstruktor von Objektelementen



  • Hi,

    zunächst einmal der code um den es geht (imho irrelevante dinge (wie diverse Elementfunktionen) hab ich mal der Übersichtlichkeit halber weggelassen):

    class InfoDialog : public MapDialog
    {
    public:
    	InfoDialog(HWND hParent = NULL, WORD wTemplate = NULL);
    };
    class MainWindow : public RootWindow
    {
    public:
    	MainWindow();
    protected:
    	InfoDialog InfoDlg;
    };
    

    MainWindow soll also eine Instanz von InfoDialog enthalten. InfoDialog::InfoDialog(...) soll aber Parameter bekommen.
    Folgendes ist leider nicht möglich (VC++ spuckt einen syntax fehler aus):

    class MainWindow : public RootWindow
    {
    public:
    	MainWindow();
    protected:
    	InfoDialog InfoDlg(hWnd, IDD_INFO); // MainWindow erbt hWnd von RootWindow!!
    };
    

    Gelöst habe ich das problem vorerst folgendermaßen:

    MainWindow::MainWindow() : RootWindow(NULL)
    {
    	InfoDialog InfoDlgInit(hWnd, IDD_INFO);
    	InfoDlg	= InfoDlgInit;
    };
    

    Diese Lösung finde ich schon äußert unbefriedigend: Das Objekt sollte sich doch eher selbst (mittels Konstruktor) initialisieren, statt eine andere Instanz diese Arbeit erledigen zu lassen und dieses dann zu kopieren.
    Richtig blöd wird das ganze aber, wenn ich im Konstruktor einen Zeiger auf das aktuelle Objekt (this) woanders speichern will (brauche das für Callback als Elementfunktion). Dann muss ich zusätzlich für den Konstruktor des Initialisierungsobjekts (InfoDlgInit) einen Zeiger auf das Objektelement (MainWindow::InfoDlg) übergeben.

    Wohl gemerkt, es geht mir hier nicht um den WinAPI-Kram (dafür brauche ich die Objekte halt blos), sondern darum, wie ich MainWindow::InfoDlg vernünftig initialisieren kann. Sprich: Parameter an dessen Konstruktor übergeben.

    Hoffe ihr könnt mir weiterhelfen, bin leider (noch) ziemlich unerfahren.. 😕
    Vielen Dank im Voraus und Gruß,
    Nils.



  • Das ist doch über die Initialisierungsliste des Konstruktors wie folgt möglich:

    MainWindow::MainWindow() : RootWindow(NULL), InfoDlg(hWnd, IDD_INFO)
    {
    }
    


  • Hi,

    dafür gibt es in C++ den Elementinitialisierer... schreckliches Wort.

    class Bla
    {
    Bla(int a, int b){}
    };
    
    class Blub
    {
    private:
    Bla a;
    public:
    Blub();
    };
    
    Blub::Blub() : Bla(10,20) // !
    {}
    

    MfG Eisflamme 🙂



  • *g* ok, deine Version is präziser.



  • Dafür war ich zu langsam ^^



  • Mach dir nix draus, ich hab auch 10 Minuten rumgerätselt, ob das jetzt wirklich mit dem Elementinitiali... also mit der Initialisierungsliste (<- danke für den Begriff, auch wenn ich mir net sicher bin, ob der viel besser ist X'D) so funktioniert. 🙂

    MfG Eisflammä



  • ah, das ging flott... thx!
    gleich mal testen. hätt ich ja auch drauf kommen können, dachte das funktioniert nur um parameter an konstruktoren in der hierachie nach "oben" zu reichen.



  • Nein, das Funktioniert auch mit built-in-Typen (z.B. int):

    class foo {
      int bar;
      foo() : bar(0) {}
    };
    


  • ja. Eben darauf bin ich dann auch gekommen ^^ und dann dachte ich mir: Mensch, dann muss das da doch auch gehn. X'D



  • okay, das funktioniert im prinzip schonmal.. danke nochmal.
    ABER, was mach ich im folgenden fall:

    class A
    {
      A(int x){y=x};
      int y;
    };
    class B
    {
      B(z=3):a(z)
      A a;
      int z;
    };
    

    der konstruktor von a wird aufgerufen, bevor z feststeht! 😞



  • Du solltest den Parameter von B nicht auch unbedingt z nennen (mal abgesehen davon das er keinen Typ bekommen hat ;)) und dann kannst du es z.B. so machen:

    class A
    {
      A(int x) : y(x) {}
      int y;
    };
    class B
    {
      B(int wert=3) : z(wert), a(wert) {}
      A a;
      int z;
    };
    


  • sorry, hab mich vertan, meinte folgendes:

    class A
    {
      A(int x){y=x};
      int y;
    };
    class B
    {
      B();
      A a;
      int z;
    };
    B::B() : a(z)
    {
      z=3 // nur ein Bsp, daß hier etwas mit z passiert, DIESES z soll a initialisieren
    };
    


  • Dann machst du es so ähnlich:

    class A
    {
      A(int x){y=x};
      int y;
    };
    
    class B
    {
      int z;
      A a;
      B();
    };
    
    B::B() : z(3), a(z)
    {
    }
    

    Zu beachten ist allerdings noch etwas bei dem Konstruktor:
    Damit z vor a initialisiert wird, muss z vor a deklariert sein in der Klasse. Die Reihenfolge in der Initialisierungsliste spielt keine Rolle, sondern die Reihenfolge der Deklaration der Variablen.



  • glaub ich kanns selber beantworten:

    class A
    {
      A(int x){y=x};
      int y;
    };
    class B
    {
      B();
      int z;
      A a;
    };
    B::B() : z(3), a(z)
    {
    };
    

    oder?



  • hehe, zeitgleich! 🙂
    naja, jetzt wirds dann leider doch off topic (bzw falsches forum):
    das prob is, daß z bei mir nich so einfach festgelegt wird wie im beispiel.
    es ist ein HWND und dem geht das füllen einer WNDCLASSEX und der aufruf von CreateWindowEx(...) voraus.
    falls du da noch weiterhelfen kannst?!?!
    werd mal schauen, ob ich das irgendwie hinbekomme..



  • Fast! 😉 Siehe meine Anmerkung. 🙂



  • Vellas schrieb:

    Fast! 😉 Siehe meine Anmerkung. 🙂

    hab doch z vor a deklariert! 🙂



  • Ops übersehen, sry. 🙂
    Zu dem anderen kann ich so nix sagen, hast da sonst nochmal ein Minimalbeispiel, wie das HWND gefüllt werden muss bzw. welche Operationen stattfinden müssen bevor "InfoDlg(hWnd, IDD_INFO);" aufgerufen werden soll?
    Ansonsten musst du wohl doch den Umweg über die temporäre Variable gehen.



  • das hab ich ihn etwa vor:

    class A
    {
      A(int x){y=x};
      int y;
    };
    class B
    {
      B();
      int z;
      A a;
    };
    B::B() : a(z)   // funktioniert nicht wie gewollt, da z noch nicht definiert
    {
      m = f();      // hier wird ein struct mit werten gefüllt
      z = g(m);     // z wird mittels dieses structs bestimmt
    };
    

    sowas dürfte funktionieren:

    class A
    {
      A(int x){y=x};
      int y;
    };
    class C
    {
      int z;
      C()
      {
        m = f();      // hier wird ein struct mit werten gefüllt
        z = g(m);     // z wird mittels dieses structs bestimmt
      };
    };
    class B
    {
      B();
      C c;
      A a;
    };
    B::B() : c() a(c.z)
    { 
    };
    

    für m hab ich mir mal die deklaration gespart...
    im prinzip sollte es so irgendwie funktionieren, oder?
    schön is das aber auch nich richtig. is dann wieder eine unnötige klasse. 😞

    noch ne andere idee, wenn ich m global mache (wäre nicht ganz unsinnig):

    B::B() : a(g(m))
    {
    };
    

    naja, werd mal schauen, was ich so hinbekomme. rumwurschteln hat ja eh imme rden besten lerneffekt! 🙂
    jedenfalls nochmal vielen dank!



  • Hi,

    also bei der Windowsprogrammierung geht es ja eigentlich immer um irgendwelche HWND-Strukturen oder so und da konstruiert man ja nichts durch den ctor sondern setzt einfach alle Werte.
    Na ja, davon abgesehen kannst du auch zur Laufzeit ein Objekt erstellen, wenn du mit Zeigern arbeitest.

    class Bla
    {
    Bla(int a, b) {}
    };
    
    class Blup
    {
    private:
    Bla* a;
    public:
    Blup(int c);
    ~Blup();
    };
    
    Blup::Blup(int c)
    {
    // mache irgendwas
    a = new Bla(x, y);
    }
    
    Blup::~Blup()
    {
    delete a;
    }
    

    Das macht man allgemein bei dynamisch bzw. zur Laufzeit erstellten Objekten so... Zu beachten ist dann aber, dass du zu einem new natürlich immer ein delete brauchst.
    Ob in deinem Fall Zeiger nötig sind, weiß ich aber gerade nicht zu beurteilen.

    MfG Eisflamme


Anmelden zum Antworten