2016-04-22 14 views
2

Hier ist ein Beispiel für meine Frage:Warum sollte der Konstruktor einer abgeleiteten Klasse den Standardkonstruktor der Basis in seiner Initialisierungsliste verwenden?

class MyBaseClass 
{ 
public: 
    MyBaseClass(): my_bool(false), my_value(0) 
    {} 
    MyBaseClass(bool b, int i): my_bool(b), my_value(i) 
    {} 

private: 
    bool my_bool; 
    int my_value; 
} 

class MyDerivedClass1 : public ::MyBaseClass 
{ 
public: 
    MyDerivedClass1(double d): my_double(d) 
    {} 
private: 
    double my_double; 
} 

class MyDerivedClass2 : public ::MyBaseClass 
{ 
public: 
    MyDerivedClass2(double d): MyBaseClass(), my_double(d) 
    {} 
private: 
    double my_double; 
} 

Warum ist nicht die MyDerivedClass1 eine oke Art und Weise meiner abgeleiteten Klasse zu initialisieren im Vergleich explizit die Basisklasse wie MyDerivedClass2 in initialisieren zu müssen?

Ich denke, ich verstehe nicht, warum ich mich nicht einfach darauf verlassen kann, dass C++ meinen Basiskonstruktor aufruft? Ich weiß, wenn ich wollte, dass sie mit etwas anderem initialisiert werden, müsste ich den anderen Konstruktor in meiner Initialisierungsliste aufrufen, aber alles, was ich will, ist der Basiskonstruktor, der sowieso aufgerufen wird.

+0

Erhalten Sie einen Fehler entdeckt? Wenn Sie den Basiskonstruktor aufrufen, sollte der Compiler automatisch den Standardkonstruktor der Basisklasse aufrufen. – NathanOliver

+0

@NathanOliver - Nein, ich erhalte keinen Fehler. Mir wurde in einer Codeüberprüfung gesagt, dass ich den Basiskonstruktor wie in MyDerivedClass2 einfügen soll und ich fragte warum. Niemand konnte mir einen guten Grund geben, ohne "Dokumentation". Also ich frage warum hier. Auch, als ich google'd um Best Practices sagte, rufen Sie den Basiskonstruktor und meine Kollegen ansässig diese Gründe auch, aber ich weiß nicht, warum ich in diesem Fall sollte. Ich hatte gehofft, dass jemand einen guten Grund hatte. – TWhite

+3

Das klingt wie ein Coding-Standard-Problem, in diesem Fall ist die Antwort wahrscheinlich etwas in der Art von "es zeigt, dass Sie es in Betracht gezogen haben und entschieden, dass Standard-Aufbau der Basis angemessen ist, und nicht nur vergessen". –

Antwort

4

Es gibt keinen Unterschied zwischen der Bereitstellung einer standardmäßig erstellten Basisklasse in der Initialisierungsliste oder deren Nichtbereitstellung. Was Sie verwenden, wenn Sie Ihren Stil haben. (oder das Unternehmen)

Im Allgemeinen würde ich sagen, Sie haben 2 Optionen (lassen Sie uns Konstruktoren außerhalb des Geltungsbereichs bleiben), vorausgesetzt, Sie initialisieren immer Ihre Mitglieder.

Option 1: Initialisieren Sie alle Mitglieder in der Init-Liste.

Diese Option sollte verwendet werden, wenn Sie C++ 98-kompatibel sind. Es hat den Vorteil, dass Sie alle Konstruktionsparameter in einer einzigen Liste definieren und so die Suche erleichtern. (Es sei denn, Sie haben 50+ Mitglieder)

Der Nachteil dieser Option ist viel Doppelarbeit, wenn Sie mehrere Konstruktoren haben.

Damit Sie 3 Varianten für sie haben können:

  • die default-initialisiert Klassen überspringen, macht dies die Liste kürzer, obwohl es schwer zu überprüfen ist, wenn Sie gedacht haben, es zu ‚vergessen‘. (Denken Sie eine Klasse von einer ptr, um es zu ersetzen)
  • Standard initialisieren alle Mitglieder, dies ist die Liste länger macht, zeigt jedoch deutlich die Absicht
  • bieten Explizit die Klasse, die Sie initialisieren, kopieren contructing mit einem tempuary

Option 2: initialisieren alle Mitglieder auf Erklärung, mit Ausnahme von Konstruktorparameter

Diese Option setzt voraus, dass alles, was in der Klassendeklaration initialisiert werden. Wiederum können Sie den Standardkonstruktor explizit aufrufen, vorzugsweise mit brained init, da runde Klammern als Funktionsdeklaration interpretiert werden.

In der Initialisierungsliste müssen Sie nur die Elemente angeben, die mit den Konstruktionsparametern verknüpft sind.

Der Vorteil dieser Option ist Lesbarkeit (besonders für große Klassen). Der Nachteil ist, dass dies Ihre Compiler-Optionen auf "moderne" Compiler beschränkt.

Basisklassen

Wenn wir wieder Basisklassen betrachten und sie betrachten, als ob sie Mitglieder waren, wäre der konsequente Weg, um sie für die Option 1 explizit zu deklarieren und sie nicht für 2-Option schreiben.

Persönlich mag ich Option 2, da ich zu oft auf Klassen mit zu vielen Mitgliedern stoße und überprüfe, ob alle Mitglieder initialisiert sind, ist mit der Hand einfacher.

Option 1 wird jedoch oft wegen Legacy verwendet, um den Code konsistent zu halten.

POD

Wichtig zu erwähnen sind die PODs (Plain alten Datentyp), wie int, double ... Wenn Sie nicht initialisieren Sie einige zufällige Daten. Daher ist es wichtig, sie unabhängig von der verwendeten Methode explizit zu initialisieren.

Fazit

Also am Ende, es ist alles eine Frage des Stils ohne funktionellen Unterschied.

2

Obwohl es in den meisten Fällen keinen semantischen Unterschied gibt und das Problem hauptsächlich im Stil liegt, gibt es einen Fall, bei dem es einen Unterschied gibt: wenn der Standardkonstruktor der Basisklasse nicht vom Benutzer bereitgestellt wird.

Der Unterschied resultiert aus der Tatsache, dass eine Base, die nicht in dem Elemente Initialisiererliste ist default-initialisierten, während ausdrücklich schriftlich Base()Wert initialisiert es, die, wenn die Standard-Konstruktor ISN Null-Initialisierung durchführt‘ t Benutzer bereitgestellt.

So:

struct A { int i; }; 
struct B : A { 
    B() : j(i) {} // may be undefined behavior 
    int j; 
}; 

struct C : A { 
    C() : A(), j(i) {} // OK; both i and j are zero 
    int j; 
}; 
+0

Werde ich immer Null sein? Ist dieser Compiler unabhängig? – TWhite

+0

Wird ich überhaupt initialisiert? Überspringt der Standardkonstruktor es nicht? – JVApen