2010-03-27 123 views
6

我想運行一個程序的1,000次迭代,所以在main中設置一個1000的計數器。我需要在每次迭代之後重新初始化各種變量,並且由於類構造函數已經寫出了所有初始化 - 我決定在每次迭代之後調用它,每次迭代的結果都存儲在main變量中。調用構造函數重新初始化變量似乎不起作用?

但是,當我調用構造函數時,它沒有任何作用......我花了一段時間才弄清楚 - 但它並沒有重新初始化任何東西!

我創建了一個完全像構造函數一樣的函數 - 所以對象會有自己的版本。當我打電話時,它會按我的預期重新初始化一切。

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 
*/ 
} 

...可能有人試圖解釋什麼,我做錯了,或者沒有工作,或者是愚蠢的或你有什麼?我的意思是 - 從心理上講,我只是想 - 廢話,我可以調用這個構造函數,並重新初始化所有這些東西。構造函數(理想情況下)只有在創建對象時才調用?

+0

*放置新*似乎是可能的。 http://stackoverflow.com/questions/6868363/how-to-recall-a-constructor-of-an-initialised-object – Eonil 2013-07-17 22:42:58

+0

'MyClass = Class();'? – 2015-06-05 20:53:21

回答

8

您的行Class();確實會調用類Class的構造函數,但它會調用它來創建「臨時對象」。由於您不使用該臨時對象,因此該行沒有任何有用的效果。

臨時對象(通常)會在它們出現的表達式的末尾消失。它們對於作爲函數參數傳遞或初始化其他對象很有用。僅在聲明中創建一個幾乎沒有用處。該語言允許它作爲一個有效的表達式,這只是對於大多數類而言它並沒有太大的作用。

C++沒有辦法在已經構建的對象上調用構造函數。 C++對象的生命週期是一個構造,一個是破壞。這就是它的工作原理。如果你想在它的生命中重置一個對象,你已經做了正確的事情,即調用一個函數來重置它。根據你的班級,你可能不需要編寫一個 - 默認的賦值操作符可能完全符合你的需要。這時候,一個臨時可以派上用場:

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

myObject = Class(); 

這將更新myObject從新鮮建造臨時的值。它不一定是最有效的代碼,因爲它會創建一個臨時的,然後複製,然後銷燬臨時的,而不是隻將字段設置爲其初始值。但除非你的班級規模龐大,否則千次不可能會花費大量時間。

另一種選擇是隻用一個全新的對象每次迭代:

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

注意Class MyClass();定義類型類的一個對象,叫MyClass的,並且不帶參數構造它。它聲明一個名爲MyClass的函數,它不接受任何參數,並返回一個Class類型的對象。推測在你的真實代碼中,構造函數有一個或多個參數。

+0

我使用構造函數,但我很少傳遞參數,儘管我知道我可以。大多數時候我只是覺得我應該在源代碼中的構造函數中設置它們。爲什麼通過main傳遞參數呢? – Azoreo 2010-03-27 21:11:08

+0

在這種情況下,如果您沒有使用構造函數參數,而且也沒有爲無參數構造函數使用正確的語法,那麼我對您的代碼編譯感到非常驚訝。無論如何,使用構造函數參數的原因是,如果你的類的對象不完全相同。以標準庫爲例,您可以指定矢量的初始大小和內容等等。 – 2010-03-27 21:19:11

+0

使用Microsoft Visual Studio C++及其內置的編譯器...如果我將構造函數聲明爲KnightsTour :: KnightsTour(例如),然後放入KnightsTour;在我的頭文件中,它會拋出錯誤,說它看起來像一個函數,但沒有參數。 Soooo ...我添加了一個空的參數列表,即「KnightsTour :: KnightsTour()」,然後是「KnightsTour();」在頭文件中 - 編譯並運行! – Azoreo 2010-03-27 21:30:36

1

是的,這不是典型的用法。創建一個重置變量的函數,並在需要時調用該方法。

0

你陷入了對C++常見的誤讀。新的C++ 0x使事情變得更清晰。

問題是結構語法看起來像一個函數調用。

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 

我認爲C++ 0x語法更清晰。

你可以用這個語法做你想做的事。但要小心它是非常先進的,你應該不是做到這一點。

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

不這樣做的主要原因是,如果'Class'的構造函數拋出,那麼對象'MyClass'處於不一致的狀態。堆棧展開將嘗試再次破壞它,產生未定義的行爲。那麼,它不會爲你寫出一個寫得很好的'operator ='或'reset'成員函數。所以如果你控制'MyClass'就沒有必要這麼做了,如果你不控制'MyClass',那麼它就會有問題;-) – 2010-03-27 21:22:52

5

在該行的閱讀,會發生什麼......

Class(); 

是你做實際上調用構造函數 - 爲正在從頭建立一個臨時的對象,然後將其立即銷燬因爲你沒有做任何事情。這非常類似於轉換爲Class,它使用構造函數調用創建一個值,除了在這種情況下沒有值轉換以便使用默認構造函數。

編譯器可能會暫時優化這個暫停,所以根本沒有構造函數 - 我不確定是否允許這樣做。

如果你想重新初始化成員,調用構造函數是不行的。將所有初始化代碼移動到另一個方法中,並從構造函數中調用該方法,而當您想要重新初始化時,則需要調用該方法。

+2

「我不確定是否允許這樣做」 - 這是,但是隻有當構造函數和析構函數都不影響程序的可觀察行爲時。因此,如果您在追蹤中查看它們是否被省略,那麼它們不能被省略。 – 2010-03-27 20:52:12

0

有了這樣的要求,我通常會寫一個clear()(公共)方法。我從構造函數,析構函數中調用它。用戶代碼可以隨時調用它。

class Foo 
{ 
    public: 

    Foo() { clear(); } 

    ~Foo() { clear(); } 

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

    private: 

    // private members 
}; 

要在這裏回答這個問題,每當它需要重新初始化類,因爲它只是初步建設後是clear()方法可以被調用。