2013-03-22 336 views
2

Andrew Koenig和Barbara E. Moo閱讀「Accelerated C++」的另一個問題,我在關於構造函數的章節(5.1)中,使用before這個例子。帶參數的構造函數初始化

他們寫

我們要定義兩個構造函數:第一個構造函數沒有參數,並創建一個空的Student_info對象;第二個參考輸入流並通過從該流讀取學生記錄來初始化該對象。

導致使用Student_info::Student_info(istream& is) {read(is);}作爲第二構造的例子

代表實際工作的讀取功能。讀取立即給這些變量新值。

Student_info

class Student_info { 
public: 
    std::string name() const (return n;} 
    bool valid() const {return !homework.empty();} 
    std::istream& read(std::istream&); 

    double grade() const; 
private: 
    std::string n; 
    double midterm, final; 
    std::vector<double> homework; 
}; 

由於read已經被定義爲Student_info類下的函數,爲什麼有必要使用第二個構造 - 這不就是雙重的工作?爲什麼不使用默認構造函數,然後函數,因爲兩者都已經定義?

回答

1

我的問題是,因爲read已被定義爲Student_info類下的函數,爲什麼需要使用第二個構造函數 - 是不是這個雙重工作?

第二個構造函數從調用方獲取參數並將其傳遞給read函數。這允許你直接實例化Student_infostd::istream

std::istream is = ....; 
Student_info si(is); // internally calls read(is) 

,而不是

std::istream is = ....; 
Student_info si; 
si.read(is);  // how could we use is if this call isn't made? Now we have to read some docs... 

爲什麼不直接使用默認的構造函數,然後因爲這兩個功能都已經定義?

因爲最好是構造一個對象,使它們處於一個連貫的有用狀態,而不是先構造它們然後初始化它們。這意味着對象的用戶不必擔心事物是否可以使用或者必須首先被初始化。例如,該功能需要一個Student_info參考:

void foo(const Student_into& si) 
{ 
    // we want to use si in a way that might require that it has been 
    // initialized with an istream 
    si.doSomethingInvolvingInputStream(); // Wait, what if the stream hasn't been read in? 
             // Now we need a means to check that! 
} 

理想的情況下,foo不應該擔心的對象已經被「初始化」或有效。

+0

所以它保存初始化所有的變量(他們的零版本)的步驟之前它寫完了嗎? 有沒有速度/功率差異,還是隻是爲了清晰? – sccs 2013-03-22 07:22:02

+1

@sccs變量首先被初始化,因爲函數是從構造函數的主體中調用的。在這個階段,所有的數據成員都已經構建完成。所以真正的原因是我在最後一段中提到的設計方面。這不僅僅是清晰度:一種在施工後必須明確初始化的類型是非常沒用的(儘管我每天都在工作中遇到它們) – juanchopanza 2013-03-22 07:23:44

+0

我剛剛看到了,謝謝!還有一個 - 是否存在沒有第二個構造函數(帶參數)的程序? – sccs 2013-03-22 07:24:55

5

這不是相反雙重的工作,它簡化了如果你創建類的單個構造每次你有時間做

std::istream is = std::cin; 
Student_info si(); 
si.read(is); 
// si.foo(); 
// si.bar(); 
// si.baz(); 
誰實例化類

來電的對象初始化

也許可以添加一些可以在構造函數中完成的其他操作。所以當你需要實例化類的時候,你不必再寫它們。如果創建10個實例,你將不得不寫

(10 -1 =)9條線,這是不適合OOP

Student_info::Student_info(istream& is) 
{ 
    read(is); 
    //foo(); 
    //bar(); 
    //baz(); 
} 

一個很好的做法,但一旦你定義像上面兩個構造函數,你可以使用類像

std::istream is = std::cin; 
Student_info si(is); 

之一的OOP的編寫可重用的主要目標,而不是自我重複的代碼,另一個目標是seperation of concerns。在很多情況下,實例化對象的人不需要知道類的實現細節。

在你的例子read函數可以是私人的,當它調用內部構造函數。這達到我們OOP的另一個概念Encapsulation

最後,這不是雙重的工作及其對軟件設計的一個很好的辦法