2010-03-27 5 views
6

Ich wollte 1000 Iterationen eines Programms ausführen, also setze einen Zähler für 1000 in main. Ich musste verschiedene Variablen nach jeder Iteration reinitialisieren, und da der Klassenkonstruktor alle Initialisierungen bereits ausgeschrieben hatte, entschied ich mich, das nach jeder Iteration aufzurufen, wobei das Ergebnis jeder Iteration in einer Variable in main gespeichert wurde.Der Aufruf eines Konstruktors, Variablen neu zu initialisieren, scheint nicht zu funktionieren.

Als ich jedoch den Konstruktor anrief, hatte es keinen Effekt ... Ich brauchte eine Weile, um es herauszufinden - aber es hat nichts reinitialisiert!

Ich habe eine Funktion genau wie der Konstruktor erstellt - also würde das Objekt eine eigene Version haben. Als ich das anrief, hat es alles reinitialisiert, wie ich es erwartet hatte.

int main() 
{ 
Class MyClass() 

int counter = 0; 

while (counter < 1000) 
{ stuff happens } 

Class(); // This is how I tried to call the constructor initially. 
      // After doing some reading here, I tried: 
      // Class::Class(); 
      // - but that didn't work either 
/* Later I used... 
MyClass.function_like_my_constructor; // this worked perfectly 
*/ 
} 

... Könnte jemand versuchen zu erklären, warum, was ich tat falsch war, oder hat nicht funktioniert, oder dumm war oder was Sie haben? Ich meine - mental, ich habe mir nur gedacht - Mist, ich kann diesen Konstruktor nennen und alles neu reinitialisieren lassen. Werden Konstruktoren (idealerweise) NUR aufgerufen, wenn ein Objekt erstellt wird?

+0

Es scheint möglich mit * Platzierung neu *. http://stackoverflow.com/questions/6868363/how-to-recall-a-constructor-of-an-initialised-object – Eonil

+0

'MyClass = Class();'? –

Antwort

8

Ihre Zeile Class(); ruft den Konstruktor der Klasse Class, aber es ruft es auf, um ein "temporäres Objekt" zu erstellen. Da Sie dieses temporäre Objekt nicht verwenden, hat die Linie keinen nützlichen Effekt.

Temporäre Objekte (normalerweise) verschwinden am Ende des Ausdrucks, in dem sie erscheinen. Sie eignen sich zum Übergeben als Funktionsparameter oder zum Initialisieren anderer Objekte. Es ist fast nie sinnvoll, nur einen in einer Anweisung zu erstellen. Die Sprache erlaubt es als einen gültigen Ausdruck, es ist nur so, dass es für die meisten Klassen nicht sehr viel macht.

Es gibt keine Möglichkeit in C++, einen Konstruktor für ein Objekt aufzurufen, das bereits konstruiert wurde. Der Lebenszyklus eines C++ - Objekts ist eine Konstruktion und eine Zerstörung. So funktioniert es. Wenn Sie ein Objekt während seiner Lebensdauer zurücksetzen möchten, haben Sie das Richtige getan, indem Sie eine Funktion aufrufen, um es zurückzusetzen. Abhängig von Ihrer Klasse müssen Sie möglicherweise keine schreiben - der Standardzuweisungsoperator könnte genau das tun, was Sie brauchen. Das ist, wenn ein vorübergehendes kann nützlich sein:

Class myObject; 
// ... do some stuff to myObject ... 

myObject = Class(); 

Das aktualisiert myObject mit den Werten aus dem frisch gebauten vorübergehend. Es ist nicht unbedingt der effizienteste mögliche Code, da er ein temporäres erzeugt, dann kopiert und dann das temporäre zerstört, anstatt nur die Felder auf ihre Anfangswerte zu setzen. Aber wenn deine Klasse nicht groß ist, ist es unwahrscheinlich, dass es eine merkliche Menge an Zeit kostet, dies 1000 Mal zu tun.

Eine weitere Option ist nur ein ganz neues Objekt für jede Iteration zu verwenden:

int main() { 
    int counter = 0; 
    while (counter < 1000) { 
     Class myObject; 
     // stuff happens, each iteration has a brand new object 
    } 
} 

Beachten Sie, dass Class MyClass(); tut nicht ein Objekt vom Typ Klasse definieren, die so genanntes MyClass, und baut es ohne Parameter. Sie deklariert eine Funktion namens MyClass, die keine Parameter akzeptiert und ein Objekt vom Typ Class zurückgibt. Vermutlich hat der Konstruktor in Ihrem echten Code einen oder mehrere Parameter.

+0

Ich benutze Konstruktoren, aber ich übergebe selten Parameter, obwohl ich weiß, dass ich kann. Meistens habe ich das Gefühl, ich sollte sie im Konstruktor im Quellcode setzen. Warum Parameter übergeben, um es über Main zu tun? – Azoreo

+0

In diesem Fall bin ich sehr überrascht, dass Ihr Code kompiliert wird, wenn Sie keine Konstruktorparameter verwenden, aber auch nicht die korrekte Syntax für parameterlose Konstruktoren verwenden. Wie auch immer, der Grund für die Verwendung von Konstruktorparametern ist, wenn Objekte Ihrer Klasse nicht alle gleich sind. Sehen Sie sich die Standardbibliothek für Beispiele an - Sie können die anfängliche Größe und den Inhalt eines Vektors und so weiter festlegen. –

+0

Verwenden von Microsoft Visual Studio C++ und es ist Compiler integriert ... Wenn ich einen Konstruktor als KnightsTour :: KnightsTour (zum Beispiel) deklarieren und dann KnightsTour setzen; in meiner Headerdatei, es wirft Fehler, sagen, es sieht aus wie eine Funktion, aber das sind keine Parameter. Soooo ... Ich habe eine leere Parameterliste hinzugefügt, d. H. "KnightsTour :: KnightsTour()" und dann "KnightsTour()"; in der Headerdatei - kompiliert und läuft! – Azoreo

1

Ja, das ist keine typische Verwendung. Erstellen Sie eine Funktion, die Ihre Variablen zurücksetzt, und rufen Sie die Methode bei Bedarf auf.

0

Sie fielen einer allgemeinen Fehllesung von C++ zum Opfer. Das neue C++ 0x macht die Dinge ein wenig klarer.

Das Problem ist, dass die Konstruktionssyntax wie ein Funktionsaufruf aussieht.

void foo(int i) { } 
class Foo { }; 

Foo(10); // construct a temporary object of type foo 
foo(10); // call function foo 
Foo{10}; // construct a temporary object of type foo in c++0x syntax 

Ich denke, die C++ 0x-Syntax ist klarer.

Sie könnten mit dieser Syntax tun, was Sie wollen. Aber Vorsicht, es ist sehr weit fortgeschritten und Sie sollten nicht tun.

MyClass.~Class(); // destruct MyClass 
new(&MyClass) Class; 
+0

Der Hauptgrund dafür ist, dass das Objekt 'MyClass' in einem inkonsistenten Zustand ist, wenn der Konstruktor von' Class' ausgibt. Das Abwickeln des Stapels wird versuchen, es erneut zu zerstören, was zu undefiniertem Verhalten führt. Das, und es bringt Ihnen nichts über eine gut geschriebene 'operator =' oder 'reset' Memberfunktion. Also, wenn du 'MyClass' kontrollierst, brauchst du das nicht, und wenn du' MyClass' nicht kontrollierst, dann fragt es nach Ärger ;-) –

5

Was in dieser Zeile Lesung passiert ...

Class(); 

ist, dass Sie in der Tat den Konstruktor aufrufen - für ein temporäres Objekt, das von Grund auf neu gebaut wird, und die dann sofort zerstört weil du nichts damit machst. Es ist sehr ähnlich wie bei der Klasse "Casting", bei der ein Wert mithilfe eines Konstruktoraufrufs erstellt wird, außer dass in diesem Fall kein Wert für die Umwandlung vorhanden ist, sodass der Standardkonstruktor verwendet wird.

Es ist möglich, dass der Compiler dieses temporär entfernt, so dass es überhaupt keinen Konstruktor gibt - ich bin nicht sicher, ob das erlaubt ist oder nicht.

Wenn Sie Mitglieder neu initialisieren möchten, ist das Aufrufen des Konstruktors nicht der richtige Weg. Verschieben Sie Ihren gesamten Initialisierungscode in eine andere Methode, und rufen Sie diesen Code in Ihrem Konstruktor auf und wenn Sie ihn stattdessen neu initialisieren möchten.

+2

"Ich bin mir nicht sicher, ob das erlaubt ist oder nicht" - es ist, aber nur wenn weder der Konstruktor noch der Destruktor Auswirkungen auf das beobachtbare Verhalten des Programms haben. Wenn Sie also eine Spur einfügen, um zu sehen, ob sie weggelassen werden, können sie nicht weggelassen werden. –

0

Mit solchen Anforderungen schreibe ich in der Regel eine clear() (öffentliche) Methode. Ich rufe es von Konstruktor, Destruktor. Benutzercode kann ihn jederzeit aufrufen.

class Foo 
{ 
    public: 

    Foo() { clear(); } 

    ~Foo() { clear(); } 

    void clear(); // (re)initialize the private members 

    private: 

    // private members 
}; 

Um die Frage hier zu beantworten, die clear() Methode aufgerufen werden kann, wenn es um die Klasse neu zu initialisieren, da es nur nach dem ersten Bau war notwendig.

Verwandte Themen