2012-09-13 67 views
4

我來自Java背景,但是我學習了C++之後,現在已經使用它編寫了幾年(主要是調試和寫入修復,而不是從頭開始設計程序)。然而,我今天坦率地遇到了一個問題,我花了很長時間才碰到它,我有點驚訝。這是不好的RAII設計?

比方說,我有一個名爲Class其頭文件包含(除其他代碼)類:

class Class1 { 
    private: 
     Class2 object; 
} 

的類2類沒有指定一個默認的構造函數。現在,在Class1的構造,我讀文件的二進制頭和使用我從解析信息初始化類2,如下面的僞代碼:

Class1::Class1(std::string) { 
    // Read some binary info from a file here 

    // Parse that binary info 

    object2 = Class2(info); 

在Java中,因爲它是不使用RAII範例,那將是完全合法的。但是,由於C++使用RAII,在我做object2 = Class2(info);時,對象2已經用其默認構造函數初始化了。我不能只是最初調用該構造函數(在Class1頭文件中),因爲我沒有創建object所需的信息。但是,我不能僅將object2作爲本地構造函數,因爲我需要其他函數才能看到/使用它。

顯然這是行不通的。這個東西的標準方法是什麼?其實我想過只是改變的Class1具有像這樣一類2指針:

class Class1 { 
    private: 
     Class2* objectPointer; 
} 

,然後調用*objectPointer = Class2(info)。然而,在我的情況下,「Class2」是一個ifstream,看起來operator=函數已被刪除,並不適用於任何一種方法。

那麼......我該怎麼做?

+0

哈哈!在<1分鐘內4個相同的答案 – Walter

+0

我不認爲說「C++使用RAII」是完全正確的。 C++啓用RAII,但不需要使用它。 –

+0

請注意,RAII是一個奇妙功能的可怕名稱。雖然名稱提示初始化,但重要的一面是破壞:每個資源都應該由一個類來管理。它沒有/反對2階段初始化(儘管你可能想盡可能避免它) –

回答

6

因爲您的object不是const,這完全合法。但是,如果要在初始化階段初始化objects,則必須提供信息。你可以做這樣的

Class1::Class1(std::string file_name) : object(InfoFromFile(file_name)) {} 

其中InfoFromFile()要麼是一個獨立的功能(在.cc文件內的匿名命名空間中聲明)或Class1靜態成員函數。如果需要比file_name更多的信息來生成Class2所需的信息,則可以將其提供給該函數。

+0

謝謝!我完全忘記了使用初始化列表的一個重點是選擇爲那個成員調用哪個構造函數,而不是默認值。我像你提到的那樣將'object'加入到列表中,果然,現在一切都很好。 – mtrewartha

2

我建議使用一個本地函數來完成讀取二進制信息,並在構造函數列表直接初始化位:

namespace { 

InfoObject readInfo(std::string s) 
{ 
// Read some binary info from a file here 

// Parse that binary info 
    return info; 
} 

} 

Class1::Class1(std::string s) 
: object(readInfo(s)) 
{ 
} 

使用指針,當然,也是一種選擇。這也是Java在Java中更自然地工作的原因(每個用戶類型都是一個指針,內部)。你可能想要使用智能指針。

5

如果「讀取和解析」部分不需要構建對象,則可以將其移動到靜態(或非成員)函數,並使用以下結果初始化成員:

Class1::Class1(std::string) : 
    object2(read_class2_info(some_file)) 
{} 

如果你實在無法將文件從對象的構造出於某種原因分開讀,不能重新分配object2後,那麼你就需要使用指針。創建對象,你會使用new

objectPointer = new Class2(info); 

然而,爲了保存自己不必搞成Rule of Three身邊時,你應該避免自己管理動態對象,而是使用一個智能指針:

std::unique_ptr<Class2> objectPointer; 

objectPointer.reset(new Class2(info)); 
1

我想你必須用dummy數據初始化object,然後在解析完成後用新數據更新它。

事情是這樣的:

Class1(std::string str) 
: object("some valid-but-meaningless data") 
{ 
    // parse info 
    object = Class2(info); 

如果這是不行的,你可能需要做解析靜態因子方法,然後傳遞給構造函數(你很可能會做私人的)信息。這樣的事情:

Class1(Info info) 
: object(info) 
{ 
    // whatever else you want 
} 

static Class1 create(std::string) 
{ 
    // parse info 
    return Class1(info); 
} 

編輯:我其實更喜歡沃爾特的答案;在初始化中使用函數是個好主意。我只是在這裏留下一些你可以考慮的替代想法。