2011-05-25 76 views
1

說我有一個private data member npublic get_n()函數的類。 例如,當輸出操作符超載時,我可以使用get_n()或使它成爲朋友並使用n。 有沒有'最好'的選擇?如果是這樣,爲什麼? 或者差異將會被優化掉嗎? 謝謝。簡單的設計選擇?

+1

爲什麼您認爲get_n()函數與輸出本身相比甚至更明顯? – 2011-05-25 13:27:54

回答

1

你已經得到了很多有點矛盾的答案,所以你無疑需要的是幾乎所有的答案都是矛盾的。

從效率的角度來看,它不可能有任何區別。只有返回值的函數無疑會內聯生成,除非您通過關閉全部優化來明確禁止發生該值。

這隻留下了一個問題,從設計的角度來看最好。至少國際海事組織,這是通常優於而不是首先有一個get_n。一旦你刪除了設計問題,你問的問題就消失了:因爲沒有get_n開始,你不能寫其他代碼,以取決於它。

這仍然留下一個小問題,你應該怎麼做,但是。這(當然)會導致更多的問題。特別是,n代表什麼樣的事情?我意識到你可能給出了一個假設的例子,但是一個好的設計(在這種情況下)取決於瞭解更多關於什麼是n以及它是如何使用的,以及其中n是成員的類型以及如何使用它也可以使用它

如果n是葉類,從中你想到沒有派生的一員,那麼你或許應該使用了直接寫入n友元函數:

class whatever { 
    int n; 

    friend std::ostream &operator<<(std::ostream &os, whatever const &w) { 
     return os << w.n; 
    } 
}; 

簡單,直接,有效。

但是,如果n是你希望使用一些成員(或使用)作爲基類,那麼你通常要使用「虛擬虛擬」功能:

class whatever { 
    int n; 

    virtual std::ostream &write(std::ostream &os) { 
     return os << n; 
    }  

    friend std::ostream &operator<<(std::ostream &os, whatever const &w) { 
     return w.write(os); 
    } 
}; 

注,然而,這假定你有興趣寫出一個完整的對象,至少在當前的實現中,這意味着寫出n的值。

至於爲什麼要這樣做事,有幾個簡單的原則,我認爲應遵循:

  1. 要麼使一些真的私人,或者把它公開。 JavaBeans可能需要公開get_n(以及公共set_n)的私有成員(例如),但仍然是一個真正的不好的想法,並且顯示了對目標方向的誤解或封裝,更不用說製造徹頭徹尾的醜陋代碼。
  2. 告訴別問。公衆get_n通常意味着你最終得到的是執行讀取/修改/寫入循環的客戶端代碼,該對象充當啞數據容器。通常最好將其轉換爲客戶端代碼描述所需結果的單個操作,並且該對象本身執行讀取/修改/寫入以實現該結果。
  3. 最小化界面。你應該努力使每個對象具有最小的接口,而不會給用戶造成過度的痛苦。消除像get_n這樣的公共功能本身幾乎總是一件好事,獨立於封裝的好處。

因爲其他人評論了關於friend功能,我將添加我的兩分錢的價值在這個問題上也是如此。聽到意見的時間非常頻繁,「應該避免朋友,因爲它破壞了封裝」。

我必須強烈反對,並進一步相信任何人認爲在學習像程序員一樣思考方面還有一些工作要做。程序員必須從抽象的角度思考,然後儘可能合理地在現實世界中實現這些抽象。

如果對象支持輸入和/或輸出,則輸入和輸出是份該對象的界面的,不管實現該接口是對象的一部分。 只有其他可能性是對象類型不支持輸入和/或輸出

這裏的要點很簡單:至少要支持常規約定,C++插入器和提取器必須寫成免費(非成員)函數。儘管如此,插入和提取與其他任何操作一樣,也是類接口的一部分,因此插入器/提取器與其他任何東西一樣(是抽象的)也是類的一部分。

我會注意到這是我爲什麼喜歡在課堂上實現中的朋友函數的一部分,正如我在上面顯示的那樣。從邏輯的角度來看,他們是班上的一員,所以讓他們看起來像班上的一員是件好事。因爲實際上它們是類的一部分 - 而C++奇怪的要求是它們被作爲自由函數實現,所以我們將重複上一次的重點:讓它們訪問類內部不可能破壞封裝,因爲實際上它們是類的一部分 - 並沒有改變這個事實,只有一個,單一的,孤獨的。

+0

謝謝你的詳細解釋,這正是我所希望的。你關於封裝和朋友函數的一般用法的觀點非常清楚和有用。 – Garp 2011-05-26 09:05:21

4

使用get_n,因爲這不是proper usage of friend。如果get_n是一個簡單的return n,編譯器很可能會自動去inline

+5

-1對*朋友不友好的OOP *。不是這種情況。一個流行的例子是具有私人構造函數的類,它們擁有工廠級的朋友。這是依賴於朋友的非常好的面向對象設計。更詳細的解釋可以在[C++ FAQ lite](http://www.parashift.com/c++-faq-lite/friends.html#faq-14.2)中找到。 – 2011-05-25 13:25:22

+2

@ Space_C0wb0y:這與之不同,因爲數據成員已公開公開。 – Puppy 2011-05-25 13:27:56

+0

@ Space_C0wb0y:感謝您的澄清(+1,因爲我喜歡失敗的概括),並且我知道* friend *的用法,但在這個特定問題的情況下,它確實不是解決方案。我將編輯我的答案更清楚。 – 2011-05-25 13:28:32

0

在這種情況下,最佳做法是讓類實現toString方法,即輸出操作符用於獲取字符串表示形式。由於這是一個成員函數,因此它可以直接訪問所有數據。它還具有額外的好處,您可以使此方法vritual,以便子類可以覆蓋它,並且您只需要一個輸出運算符的基類。

+0

它已經有一個'toString'方法 - 流插入操作符。 – Puppy 2011-05-25 13:46:52

+0

@DeadMG:流插入操作符不是一個方法(對於我來說就是指*成員函數*)。它總是必須是一個自由函數(對於用戶定義的類型)。 – 2011-05-25 13:52:25

2

我會回答一個問題,你的問題:

  • 你爲什麼要創建擺在首位公開get_n()
+0

這是一個虛擬的例子。我可以有一個私有sz成員和size()const公共函數的簡單容器。 – Garp 2011-05-25 13:58:56

+0

@Garp:那是一個修辭問題。 – 2011-05-25 14:00:11

0

運營商可以在不使用friend的情況下實施嗎?是的 - 不要使用friend。沒有 - 製造friend