2010-09-29 5 views
15

Ich erben eine Klasse, und ich möchte einen seiner Konstruktoren aufrufen. Allerdings muss ich einige Dinge (die nichts von der Basisklasse erfordern) vor dem Aufruf verarbeiten. Gibt es eine Möglichkeit, wie ich es später aufrufen kann, anstatt es auf der Initialisierungsliste anzurufen? Ich glaube, das kann in Java und C# gemacht werden, aber ich bin mir nicht sicher über C++.Rufen Sie einen Basisklassenkonstruktor später (nicht in der Initialisierungsliste) in C++

Die Daten, die ich für den Konstruktor übergeben muss, können später nicht neu zugewiesen werden, so dass ich nicht einfach einen Standardkonstruktor aufrufen und später initialisieren kann.

Antwort

27

Gibt es eine Möglichkeit, ich kann es später nur aufrufen, anstatt es auf der Initialisierungsliste aufzurufen?

Nein, das geht nicht. Der Basisklassenkonstruktor muss in der Initialisierungsliste aufgerufen werden und muss zuerst aufgerufen werden.

In der Tat, wenn Sie es dort weglassen, wird der Compiler nur den Aufruf implizit hinzufügen.

Ich glaube, dass dies in Java und C# getan werden kann, aber ich bin mir nicht sicher über C++.

Weder C# noch Java erlauben dies auch.

Was Sie können tun, ist jedoch eine Methode aufrufen als Argument der Basisklassenkonstruktor Anruf. Dieser wird dann vor dem Konstruktor verarbeitet:

class Derived { 
public: 
    Derived() : Base(some_function()) { } 

private: 
    static int some_function() { return 42; } 
}; 
+1

Danke, dachte nicht darüber nach, nur eine Funktion aufzurufen, so dass es funktionieren wird, aber es wird ein bisschen unordentlich sein, weil der Konstruktor 2 Parameter hat. Ich werde diese Antwort akzeptieren, wenn ich kann (es sei denn, es kommt natürlich eine bessere heraus). Übrigens, du hast recht, dass du das nicht in Java und C# machen kannst, ich habe mir gesagt, dass es in Java möglich ist, weil es 'super (...)' im Methodenhauptteil verwendet hat, aber jetzt habe ich es bemerkt muss die erste Zeile sein. – placeholder

+4

+1 Sie sollten some_function() statisch machen, um die Tatsache zu dokumentieren, dass keine Instanzvariablen der Klasse verwendet werden (die nicht initialisiert wurden). –

+0

Interessant, noch nie zuvor gesehen. Ich nehme an, dass die aufgerufene Funktion eine abgeleitete Klassenfunktion sein kann. – PatrickV

-2
struct base{ 
    base(int x){} 
}; 

struct derived : base{ 
    derived(int x) : base(x){} 
}; 

Dies ist, wie Basisklassenkonstruktoren in C++ von der Initialisierungs-Liste der abgeleiteten Klasse aufgerufen werden.

+4

Das ist nicht, was er fragt. –

1

IMHO Ich glaube nicht, dass es möglich ist, den Aufruf des Basisklassenkonstruktors auf die von Ihnen erwähnte Weise zu verschieben.

0

Wow, wir waren alle einmal jung. Diese Antwort wird nicht funktionieren, also benutze sie nicht. Inhalt für historische Zwecke.

Wenn Sie die volle Kontrolle über die Basisklasse haben, würde ich empfehlen, eine geschützte Methode Hinzufügen der Klasse Initialisierung zu tun, es virtuell machen, und setzen Sie die abgeleiteten Klasse Implementierungsdetails in ihn, bevor er seine Basis ruft:

+0

Leider habe ich keine Kontrolle über die Basisklasse. – placeholder

+0

Sie können Ihr Ziel dann möglicherweise nicht erreichen. Wenn Sie mehr Code posten, können wir uns vielleicht etwas einfallen lassen, aber das habe ich noch nie in C++ gesehen. – PatrickV

+0

Ich mag die Idee nicht. Zweiphasige Konstruktion ist immer fehleranfällig. – sbi

11

Wie von mehreren Personen gesagt wurde, können Sie den Aufruf eines Basisklassenkonstruktors nicht verzögern, aber Konrad has given a good answer, der Ihr Problem gut lösen könnte. Dies hat jedoch seine Nachteile (z. B. wenn Sie mehrere Funktionen mit Werten initialisieren müssen, deren Berechnungen Zwischenergebnisse aufweisen). Um das Problem der festen Initialisierungsreihenfolge durch unter Verwendung von zu lösen, ist hier eine andere Möglichkeit .

Angesichts der festen Reihenfolge der Initialisierung, wenn Sie Kontrolle über die abgeleitete Klasse haben (und wie sonst würden Sie kommen, um mit einem seiner Ctors Geige?), Können Sie in einer privaten Basis schleichen, so dass es vor der anderen Basis wird initialisiert wird, die mit der privaten Basis bereits berechneten Werten kann dann initialisiert werden:

class my_dirty_little_secret { 
    // friend class the_class; 
public: 
    my_dirty_little_secret(const std::string& str) 
    { 
    // however that calculates x, y, and z from str I wouldn't know 
    } 
    int x; 
    std::string y; 
    float z; 
}; 

class the_class : private my_dirty_little_secret // must be first, see ctor 
       , public the_other_base_class { 
    public: 
    the_class(const std::string str) 
     : my_dirty_little_secret(str) 
     , the_other_base_class(x, y, z) 
    { 
    } 
    // ... 
}; 

Die my_dirty_little_secret Klasse ist so eine private Basis dass Benutzer von the_class es nicht benutzen können, alle ihre Sachen sind auch privat, mit ausdrücklicher Freundschaft, die nur the_class Zugang zu ihm gewährt. Da es jedoch zuerst in der Basisklassenliste aufgeführt wird, wird es zuverlässig vor the_other_base_class erstellt, was auch immer es berechnet, kann verwendet werden, um das zu initialisieren.
Ein schöner Kommentar in der Basis-Klassenliste verhindert hoffentlich, dass andere Dinge durch Refactoring brechen.