2012-05-21 96 views
6
class Person { 
private: 
    string firstName; 
    string lastName; 
public: 
    Person() {} 

    Person(ifstream &fin) { 
     fin >> firstName >> lastName; 
    } 

    void print() { 
     cout << firstName 
      << " " 
      << lastName 
      << endl; 
    } 
}; 

int main() { 
    vector<Person> v; 
    ifstream fin("people.txt"); 

    while (true) { 
     Person p(fin); 
     if (fin == NULL) { break; } 
     v.push_back(p); 
    } 

    for (size_t i = 0; i < v.size(); i++) { 
     v[i].print(); 
    } 

    fin.close(); 
    return 0; 
} 

請你解釋一下,下面的代碼片段如何工作? if(fin == NULL){break; }C++,使用ifstream讀取文件

fin是堆棧上的一個對象,而不是一個指針,所以它不能成爲NULL。 我無法在ifstream類中找到重載的運算符==函數。 所以我不明白這段代碼如何工作。

回答

3

istreamostream的基類具有隱式轉換 函數,它們允許它們用作布爾值;在pre-C++ 11, 中隱式轉換爲void*

這個轉換的結果永遠不會被用作 指針,類似fin == NULL這樣的代碼對C++和標準流的理解非常差。的 寫的第一循環中的慣用方法是定義一個默認構造函數和 operator>>Person,然後寫:

Person p; 
while (fin >> p) { 
    v.push_back(p); 
} 

(雖然我吧:你真的應該測試返回值的 fin.close(),而不是如果失敗返回0

fin.close(); 
return fin ? EXIT_SUCCESS : EXIT_FAILURE; 

+0

儘管我同意這可能是最好的做法,但我從未見過**代碼,它測試關閉是否成功,並調整返回值。就我個人而言,我永遠不會調用'close',而是依賴於RAII--但幸運的是,我可以通過編寫不能實現強大IO的代碼而逃脫。 –

+0

@KonradRudolph:我猜想依賴於RAII意味着析構函數不會測試關閉是否成功。沒有辦法將這樣的錯誤條件傳輸給調用者(除非你使用全局變量)。 –

+0

@Frerich當然。就像我說的那樣,我可以放棄使用非強健的IO。懶惰,我知道,但它使代碼更簡單,更清潔。 –

2

這不是多麼ST大量的應該被使用。誠然,這(不幸的是!)編譯,甚至做「正確」的事情。但不要寫這樣的代碼。編寫這些代碼的人可能認爲他們很聰明。

但是他們真正做的是通過引入一個新的,非傳統的API來打破C++程序員的期望,而沒有真正的優勢。

此代碼從輸入流中初始化Person類型的對象。不幸的是,通過這樣做,代碼放棄了在閱讀對象時測試錯誤的機會。這不好。一個對象應該不是有一個接受輸入流的構造函數,它應該重載operator>>

+0

在這裏扮演惡魔的主張:我認爲將一個流傳遞給構造函數非常合理。您可以使用異常來指示錯誤,並避免可能存在未初始化對象的問題(與您建議的替代方法不同,它允許構建對象但不使用'operator >>')。 –

+0

@Frerich原則上,我完全同意你的看法。這也是爲什麼我說這是一個聰明的程序員,而不是詹姆斯,他認爲這是一個對流不懂的人。但它仍然打破了期望,並且可能不是C++構建現有流庫頂層的好主意。流可以做得更好,但是然後建立一個自己的庫,不要建立在現有的工作模式上,工作方式不同。 –