2009-05-06 3 views
2

Ich habe einige Code wurde die Überprüfung, die wie folgt aussieht:Verzögerte Konstruktor in C++

class A; // defined somewhere else, has both default constructor and A(int _int) defined 
class B 
{ 
public: 
    B(); // empty 
    A a; 
}; 

int main() 
{ 
    B* b; 
    b = new B(); 
    b->a(myInt); // here, calling the A(int _int) constructor, 
    //but default constructor should already have been called 
} 

funktionierts? Aufruf eines bestimmten Konstruktors nach dem Standard wurde bereits aufgerufen?

Antwort

15

Dieser Code ruft den Konstruktor von a nicht auf. Es ruft A::operator()(int).

Aber Wenn Sie explizit einen Konstruktor für ein Objekt aufrufen, das bereits erstellt wurde, sind Sie gut in undefiniert Behavior-Land. Es scheint in der Praxis zu funktionieren, aber es gibt keine Garantie, dass es das tut, was Sie erwarten.

+0

Dies scheint der Fall zu sein, danke. –

+0

Es ruft nur "A :: operator() (int)", wenn diese Funktion deklariert ist? Ich bin beeindruckt, dass Sie feststellen konnten, dass diese Funktion deklariert wurde! –

+2

@Richard: Ich bin mir nicht sicher, worauf Sie hinaus wollen. Wenn die Funktion nicht deklariert wurde, wird der Code nicht kompiliert. Unter der Annahme, dass der Code * kompiliert, bedeutet dies, dass der Operator definiert werden muss. Es gibt keine Mehrdeutigkeit. Die Syntax, die man benutzt, kann * niemals * einen Konstruktor aufrufen, wenn man das erreicht. Um das zu tun, müssten Sie stattdessen b-> a :: A (myInt) schreiben. Die in Richs Frage gezeigte Syntax kann * nur * Operator() aufrufen. – jalf

1

Dies ruft nicht den Konstruktor, und this Antwort deckt die einzige mögliche Erklärung für das, was passiert.

Die einzige standardisierte Möglichkeit einen Konstruktor auf einem vorhandenes Objekt zu nennen, ist die Platzierung zu nutzen, um neue, (nach der vorherige Instanz zerstört wurde):

void foo (A * a) { 
    a->~A();   // Destroy previous instance 
    new (a) A(myInt); // Construct new object in same location 
} 
+0

Platzierung neu kann gefährlich sein, wenn der Konstruktor Nebenwirkungen hat (z. B. die Anzahl der lebenden Objekte zählen). Es ist am besten für den beabsichtigten Zweck überlassen, das Standardspeicherverwaltungssystem zu ersetzen. – Ari

+0

@Ari. Sicher. Aber es ist die einzige Möglichkeit, einen Konstruktor für ein bereits konstruiertes Objekt aufzurufen (wenn Sie das vorhaben). –

+0

Eigentlich muss man erst das Objekt dekonstruieren: b-> a. ~ A(); vor dem Placement neu. Placement new funktioniert nur mit einem rohen, ausgerichteten Speicher. – MSalters

2

Sie

andere Konstruktor in der Klasse B machen können

B (int _int): a (_int) {}

in diesem Fall, wenn Sie b = new B (myInt) schreiben;

Above-Code wird nicht verzögern Ihre Konstruktorcode der Klasse A.

Sie nicht brauchen, b- anrufen> a (myInt)

+0

Es ist nicht legal C++. Sie sollten "Ja, es wird funktionieren" aus Ihrer Antwort entfernen, sonst werden Sie möglicherweise abgemeldet. –

+0

@Richard Corden: fertig –

+1

Ich sehe kein ilegal C++ in diesem Kommentar – piotr

0

Sie sollten nur die A nennen (int) Konstruktor aus dem B() Konstruktor oder machen Sie einen B (int) -Konstruktor, der auch den A (int) -Knoten aufruft.

Die beste Vorgehensweise besteht darin, beides zu haben, das Standard-Setup für einen Standard-Int für A und das B (int) für Init A (Int).