2009-10-05 8 views
5

ich einige Codes zu überprüfen und ich habe eine Menge davon zu sehen:init oder zu konstruieren

class Foo 
{ 
public: 
    Foo() 
    { 
    // 'nuffin 
    } 

    void init() 
    { 
    // actual construction code 
    } 
} ; 

Der einzige Vorteil, den ich sehen kann, ist, wenn Sie ein Foo erstellen, ohne einen Zeiger zu verwenden und Sie wollen um seinen Baucode bis später zu halten, dann können Sie.

Ist das eine gute Idee oder eine schlechte Idee?

+2

Ich bin ein bisschen verwirrt, dass Sie Ihre Frage als sprachunabhängig (und nicht die Zielsprache) positionieren, während die Frage über das Überprüfen von Code ist. Ich dachte, dass das Überprüfen von Code stark mit der zu überprüfenden Sprache verbunden wäre. Wenn nicht, warum benutzen wir nicht dieselbe Sprache? ;-) – KLE

+0

Ich habe deine Frage so bearbeitet, dass der Code Syntax-Färbung bekommt. Anstatt PRE zu verwenden, setzen Sie 8 Leerzeichen vor jede Zeile. – KLE

+1

@KLE - vor jeder Codezeile befinden sich jetzt eine Reihe von Leerzeichen. Sie sollten nur 4 Leerzeichen benötigen, um die Syntaxfarbe zu erhalten. Hier passiert etwas Lustiges. –

Antwort

3

Im Allgemeinen stimme ich zu, dass es etwas zu vermeiden ist. Aber etwas, was keine der Antworten bisher angesprochen hat, ist die Möglichkeit, dass die Initialisierung fehlschlagen kann. Konstruktoren können nicht fehlschlagen, also wenn Ihr Konstruktor Speicher reserviert oder eine Datei öffnet oder irgendetwas anderes, das möglicherweise fehlschlägt, müssen Sie eine Möglichkeit, dem Aufrufer mitzuteilen, dass ein Fehler aufgetreten ist. Wenn Sie die Initialisierung im Konstruktor ausführen, müssen Sie über ein Flag verfügen, das angibt, ob die Initialisierung erfolgreich war oder nicht, und sicherstellen, dass der Aufrufer dieses Flag überprüft.

Wenn Sie eine separate init() Routine haben, die vor allem anderen Werke genannt werden müssen, sind die Anrufer eher dass Return-Code zu überprüfen, als ein didInitializationSucceed() Verfahren nach Erstellen des Objekts aufzurufen.

+2

In C++ wirft ein Konstruktor eine Ausnahme (der Normalfall) oder gibt eine 0 zurück (wenn er mit (nothrow) erstellt wurde). Es wird ein teilweise konstruiertes Objekt nicht verlassen. –

4

Ich mag es nicht. Es scheint mir, dass nach der Konstruktion ein Objekt ... nun ... konstruiert werden sollte. Dieser Code lässt es stattdessen in einem ungültigen Zustand, der fast nie eine gute Sache ist, fast .

 

Wiesel Wort für unvorhergesehene Umstände zu berücksichtigen, eingesetzt.

0

Im Allgemeinen sollte der Quellcode so einfach wie möglich sein, und Ihr Beispiel wird ohne den Kontext dargestellt, also ist es nur komplizierter als notwendig und daher ist Ihr Beispiel eine schlechte Idee.

Es kann jedoch einige semantische Kontexte geben, in denen es sinnvoll sein kann, nicht initialisierte Objekte auszuliefern - zum Beispiel, wenn der Kontext einen Container benötigt, aber erst später initialisiert werden soll Die Initialisierung ist langsam und/oder die Objekte werden möglicherweise nicht benötigt. In diesen Fällen kann die zusätzliche Komplexität etwas anderes vereinfachen.

1

Ich glaube, Konstruktor sollte grundsätzlich die init() Teil auch tun. Sofern das Objekt nicht vollständig aufgebaut ist, sollte es nicht verwendet werden.

Auch die Initialisierung im Konstruktor ermöglicht die Verwendung von RAII. Der grundlegende Punkt von RAII besteht darin, eine Ressource durch ein lokales Objekt darzustellen, das im Konstruktor initialisiert wird, so dass der Destruktor des lokalen Objekts die Ressource freigibt. Auf diese Weise kann der Programmierer nicht vergessen, die Ressource freizugeben.

2

Zweistufige Konstruktion wird im Allgemeinen als eine schlechte Idee betrachtet, wenn es Methoden für die Klasse gibt, die davon abhängen, dass sich das Objekt in einem initialisierten Zustand befindet. Im Allgemeinen bevorzuge ich Konstruktoren, die garantieren, dass das Objekt in einem guten Zustand ist, oder wenn dies nicht möglich ist (vielleicht weil einige der Argumente für den Konstruktor ungültig waren), eine Ausnahme auslösen, so dass es nie Instanzen Ihrer Klasse gibt in einem schlechten Zustand.

Anforderung der Verbraucher Ihres Objekts zu erinnern, um init() anrufen ist eine schlechte Idee, weil sie nicht.

1

Ein Fall, wo dies möglicherweise gilt, ist, wenn "Foo" ein Attribut einer anderen Klasse ist und nicht vollständig erstellt werden kann, bevor die Elternklasse ausgeführt wird. Nur dann kann "Foo" "ausgefüllt" werden.

0

Der Unterschied besteht darin, dass die Initialisierung nach dem Aufruf des Konstruktors der Superklasse erfolgt, aber bevor in Ihrem lokalen Klassenkonstruktor Code ausgeführt wird. Daher kommt es wirklich auf Ihre Bedürfnisse an.

+0

In welcher Sprache würde das passieren? Wenn Sie ein Objekt mit dieser Methode konstruieren, wird jeder Superklassenkonstruktor ausgeführt, der Klassenkonstruktor wird ausgeführt und dann wird init() aufgerufen. –

0

Obwohl es nicht als eine normale oder bevorzugte Art der Konstruktion von Objekten betrachtet werden kann, unter bestimmten Umständen, die vielleicht ein Weg zu gehen. Zum Beispiel müssen Sie möglicherweise ein Objekt konstruieren, nur um seine Existenz anzuzeigen (in einer Liste, wo der Zähler zählt usw.), aber um es später nur dann zu initialisieren, wenn dieses bestimmte Objekt zum ersten Mal als Initialisierung der gesamten Objektgruppe verwendet wird Nimm dir zu viel Zeit.

In diesem Fall ist es gut, die Tatsache offen zu legen, dass das Objekt möglicherweise nicht initialisiert wird, indem eine Methode wie isInitialized() einbezogen wird. Auch so können Sie die Initialisierung auf einen anderen Thread übertragen, um den Hauptthread der Anwendung nicht zu blockieren.

1

In einigen Sprachen (lesen: C++) können Sie einen Konstruktor nicht von einem anderen Konstruktor aufrufen. Wenn Sie also einen gemeinsamen Teil mehrerer Konstruktoren haben möchten, müssen Sie ihn in eine separate Methode einfügen, und ich habe den Namen gesehen init() verwendet dafür. Aber davon sprichst du nicht?

+0

+1: Sogar in Sprachen, wenn Sie einen anderen Konstruktor aufrufen können (lesen Sie: Java), können einige Einschränkungen (wie Sie es als eine erste Sache im anderen Konstruktorrumpf nennen), die Sie möglicherweise umgehen möchten. In diesem Fall würde ich die Methode init() jedoch als privat implementieren. – quosoo

1

Ich verwende den Konstruktor und init, wenn ich Objekte, die auf einem Datenbankaufruf basieren, instanziiere. Also, wenn ich ein leeres Objekt brauche, damit ich es auffüllen und dann in der Datenbank speichern kann, konstruiere ich ohne Parameter und rufe init() nicht auf. Wenn ich die Objektelemente aus der Datenbank abrufen muss, gebe ich contruct($param) ein und übergebe den $ param an init($param).

Verwandte Themen