Probleme mit zwei Klassen - Error: "No matching function for call to *constructor*"



  • Hey,
    vielleicht könnt ihr einem Neuling eben schnell helfen:

    class A {
          public:
                 A(int data);
          private:
                  int mData;
    };
    class B {
          public:
                 B();
          private:
                  A mMember;
    };
    
    A::A(int data): mData(data) {}
    B::B() {mMember = A(5);} //Hier tritt der Fehler auf!
    

    Der Fehler lautet: no matching function for call to `A::A()'
    Als "Note" schlägt er mir die beiden Konstruktoren von A vor, also den von mir geschriebenen und den Kopierkonstruktor.

    Ich benutze Dev-C++ 4.9.9.2

    Also wenn ich das richtig verstanden habe, möchte er, dass ich "mMember" auch initialisiere mithilfe eines Konstruktors, aber das tue ich doch!?

    Danke im Voraus!



  • Im Konstruktor von A hast du es doch schon richtig gemacht! Der Konstruktor von B muss genau so implementiert werden.



  • Ah okay danke, ich dachte das könnte man bei Klasseninstanzen nicht so einfach machen.

    Aber schau dir mal das hier an:

    class A {
          public:
                 A(int data);
                 int mData;
    };
    class B {
          public:
                 B();
                 A mMembers[3];
                 void init();
    };
    
    A::A(int data): mData(data) {}
    
    B::B() {
         init();
    }
    void B::init() {
         for (int i=0; i<3; ++i)
               mMembers[i] = A(i);
    }
    

    EDIT: habe das Beispiel mal als Array gestaltet, sodass es mehr Sinn macht, eine Init-Funktion zu verwenden.

    wenn ich im Konstruktor jetzt eine Init-Funktion aufrufen möchte, kommt genau das gleiche Problem, und das kann ich ja nicht so einfach umgehen (oder?). Wie könnte man das denn beheben?



  • Vorweg mal die Lösung für "ohne Array": du musst die Initializer-List verwenden.
    So wie du bei A::A das Member "mData" initialisierst, kannst (bzw. musst) du in B::B auch das Member "mMember" initialisieren.

    Bei "mData" wäre es nicht nötig, da "mData" einfach in "int" ist, und der muss nicht unbedingt initialisiert werden.

    Da "A" aber eine Klasse ohne Default-Constructor ist, musst du die Constructor-Parameter angeben, also so:

    B::B()
        : mMember(5) // A::A(int data) wird verwendet, mit data = 5
    {
        // mMember = A(5); // hier nichtmehr notwendig
    }
    

    Zum 2. Beispiel mit Arrays: das geht in C++ 98 bzw. 03 nicht. (In C++0x schon wenn ich mich richtig erinnere, nur der neue Standard ist noch nicht fix, und vorhandene Compiler unterstützen erst einen kleinen Teil der neuen Features)

    Was du natürlich machen kannst, ist einen Default-Constructor für A zu definieren. Dann geht beide Beispiele ohne Änderungen.



  • Ahh okay, vielen Dank. So funktioniert es.
    Dass die Initializer-List so unumgänglich ist, wusste ich gar nicht.
    Naja wie auch immer, habe jetzt einen Defaultconstructor geschrieben. Jetzt werden die Objekte von A automatisch im Konstruktor von B erstellt und in der init-Funktion verändere ich nur die Werte.
    Vielen Dank!



  • PeterPain schrieb:

    Ahh okay, vielen Dank. So funktioniert es.
    Dass die Initializer-List so unumgänglich ist, wusste ich gar nicht.

    Ist sie, ja. Sämtliche Member und Basisklassen müssen vollständig initialisiert (=konstruiert) sein, bevor der "Rumpf" des Konstruktors losläuft, d.h. vor der "{" Klammer.
    Daher muss man entweder Konstruktor-Parameter angeben, oder die Klasse des Members/die Basisklasse muss einen Default-Konstruktor haben.

    Natürlich kann man sich über Zeiger/Container behelfen, wenn das direkte Initialisieren in der Initializer-List aus irgend einem Grund nicht möglich/zu umständlich wäre, und man die Klassen nicht abändern kann (=ihnen einen Default-Konstruktor verpassen).


Anmelden zum Antworten