2011-09-21 110 views
0

此問題標題取自Scott Meyers的Effective C++第3版中的項目#23的標題。他用下面的代碼:將非會員非朋友函數加入到成員函數

class WebBrowser { 
public: 
    void clearCache(); 
    void clearHistory(); 
    void removeCookies(); 

    //This is the function in question. 
    void clearEverything(); 
}; 

//Alternative non-member implementation of clearEverything() member function. 
void clearBrowser(WebBrowser& wb) { 
    wb.clearCache(); 
    wb.clearHistory(); 
    wb.removeCookies(); 
}; 

雖然指出下面的替代非成員非友元函數是封裝比成員函數clearEverything更好的()。我想這個想法的一部分是,如果有更少的成員函數提供訪問權限,那麼訪問WebBrowser的內部成員數據的方法就會少一些。

如果您接受此功能並且創建此類外部非功能函數,您會將它們放在哪裏?這些功能仍然與班級緊密相連,但他們不再是班級的一部分。將它們放在班級的相同CPP文件,庫中的另一個文件中,或者放在什麼地方是好習慣嗎?我主要來自C#背景,而且我從未擺脫過對所有東西都渴望成爲一個類的一部分的渴望,所以這使我感到有些困惑(雖然聽起來很傻)。

回答

1

通常,你會把它們放在關聯的命名空間中。這有點像C#中的擴展方法。

問題是,在C#中,如果你想製作一些靜態函數,它們必須在一個類中,這很荒謬,因爲根本沒有OO - 例如Math類。在C++中,您可以使用正確的工具來完成這項工作 - 命名空間。

0

我做了很多。我一直把它們放到與其他類成員函數相同的.cpp文件中。我不認爲有任何二進制大小的開銷,取決於你把它們放在哪裏。 (除非你把它放在標題中:P)

0

如果你想沿着這條路走下去,clearEverything應該放在頭文件(聲明)和類的實現中,因爲它們緊密耦合,似乎是放置它們的最佳位置。

但是我會傾向於將它們作爲類的一部分 - 因爲將來您可能有其他事情要清除,或者可能有更好或更快的實現來實現clearEverything,例如丟棄數據庫並重新創建表

+1

如果您發現稍後需要它們,您可以隨時將其添加到課程中,但無法刪除它們。如果你不需要'clearEverything()'來訪問類內部,就把它放在外面。如果讓它訪問內部變得很重要,那麼爲這個類編寫一個成員函數(並且可以選擇'clearEverything()'來調用它)。 –

1

所以clearEverything是一種非常必要的便利方法。但是由您決定是否合適。

這裏的哲學是類定義應儘可能最小化,只提供一種方法來完成某些事情。這樣可以降低單元測試的複雜性,替換替代實現中涉及的全部類的難度,以及可能需要由子類覆蓋的函數的數量。

一般而言,您不應該具有僅調用其他公共成員函數序列的公共成員函數。如果你這樣做,這可能意味着:1)你的公共接口過於細緻/細化或者不適當,被調用的函數應該是私有的,或者2)該函數應該是真正的類外部的。

汽車比喻:喇叭通常與您的剎車一起使用,但爲了同時進行這兩種操作,添加一個新的踏板/按鈕是很愚蠢的。結合Car.brake()Car.honk()是由Driver執行的功能。但是,如果Car.leftHeadLampOn()Car.rightHeadLampOn()是兩個單獨的公共方法,則它可能是過度細化控制的示例,並且設計人員應該重新考慮給予Driver單個Car.lightsOn()開關。

在瀏覽器示例中,我傾向於同意Scott Meyers的看法,認爲它不應該是成員函數。但是,將其放入瀏覽器名稱空間也可能不合適。也許最好讓它成爲控制Web瀏覽器的東西的一員,例如GUI事件處理程序的一部分。 MVC專家隨時可以從這裏接管。

+0

已投票。我會告訴你斯科特的想法,處理它在哪裏。他提到stdc庫如何通過將這些輔助函數添加到不同的.cpp/.h文件來執行相同的操作,並且#include只是您需要的那些函數。 – Eric