2010-04-06 48 views
13

向類中添加功能可以通過添加一個方法或定義一個將對象作爲其第一個參數的函數來完成。我知道大多數程序員會選擇添加實例方法的解決方案。在實例方法和自由函數之間進行選擇?

但是,我有時更喜歡創建一個單獨的函數。例如,在下面的示例代碼中,將AreaDiagonal定義爲自由函數而不是方法。我覺得這樣更好,因爲我認爲這些功能提供了增強功能,而不是核心功能。

這是否被認爲是好的/壞的做法?如果答案是「取決於」,那麼決定添加方法或定義單獨函數的規則是什麼?

class Rect 
{ 
public: 
    Rect(int x, int y, int w, int h) : 
     mX(x), mY(y), mWidth(w), mHeight(h) 
    { 
    } 

    int x() const { return mX; } 

    int y() const { return mY; } 

    int width() const { return mWidth; } 

    int height() const { return mHeight; } 

private: 
    int mX, mY, mWidth, mHeight; 
}; 


int Area(const Rect & inRect) 
{ 
    return inRect.width() * inRect.height(); 
} 


float Diagonal(const Rect & inRect) 
{ 
    return std::sqrt(std::pow(static_cast<float>(inRect.width()), 2) + std::pow(static_cast<float>(inRect.height()), 2)); 
} 
+0

一個側面說明,使用pow的恆定冪數是2,相對於自己拼出x * x + y * y + z * z的效率極低。 – 2010-04-06 19:38:57

+0

@Mark B:謝謝,我不知道。 – StackedCrooked 2010-04-06 21:34:31

+1

查看經典_ [非成員函數如何改進封裝](http://drdobbs.com/cpp/184401197)_。 (「當你認爲封裝時,你應該考慮非成員函數」)另見http://stackoverflow.com/q/1692084/140719。 – sbi 2011-11-25 10:29:09

回答

14

GoTW #84根據std::string探索了這個問題。他傾向於相反的想法:大多數職能應該是全球性的,除非他們真的需要成爲會員。

我想說大多數現代C++趨向於相同的想法。例如,如果您通過Boost查看,則可以使用免費功能完成相當多的操作。

+4

我喜歡這篇文章中所包含的Scott Meyers的這句名言: >我會從這句話開始:如果您正在編寫一個可以作爲成員或非朋友非成員實現的函數,那麼您應該更願意將其作爲非成員函數來實現。該決定增加了類封裝。當你認爲封裝時,你應該考慮非成員函數。 – 2010-04-06 18:34:42

+2

我唯一的可能就是這個名字空間的污染。浮點幾何::區域(const Geometry :: Rect&r)比浮點幾何:: Rect :: Area()更好嗎?您並不是真的希望自由函數Area位於全局名稱空間中,因此您需要將其放入命名空間。在這一點上,它看起來像一個靜態類函數。 – jmucchiello 2010-04-06 18:43:36

+2

@jmucchiello:是的,大部分免費函數都應該在命名空間中。我不認爲這看起來像靜態成員函數 - 我習慣於'x :: y'這個意思是「在命名空間x中的函數y」。 – 2010-04-06 18:54:17

1

我想說這取決於你的目標是什麼。如果該功能是一個成員函數,那麼你可以使用。和 - >符號,它更好地與課堂相結合。它也允許多態性。如果你希望你的函數是虛擬的,它需要是一個成員函數。

但是,有一種思想認爲,只有在需要時才能使函數成員函數更好地封裝。因此,如果函數實際上不需要訪問成員變量(大概是因爲它可以完成公共函數需要做的事情),那麼您將它作爲一個單獨的函數,而不是該類的成員。這樣,即使意外,它也不會弄亂內部。

另一個考慮因素是,如果它不是成員函數,則不必擔心其他類型是否可以轉換爲現在是該函數的第一個參數的類型。有時候這是理想的,有時候不是。如果它是一個成員函數,那麼這不是一個問題(或一個機會,取決於你想要做什麼)。

個人而言,我不喜歡獨立於類的函數,但是當您無法控制類時,或者您無法爲了兼容性而對其進行更改時,通常會被迫以這種方式編寫函數原因或什麼。

真的,我認爲這歸結於對你最重要的事情以及你真正想做的事情。我認爲讓函數成爲類的一部分使得它更易於使用,並且更加面向對象,但是如果限制對類的私有成員有多少訪問權限,則更好。

2

如果您想與其他無關的類一起使用它,它應該是一個帶覆蓋的自由函數。

例如,您可以覆蓋float Area(Hexagon const &)float Diagonal(Hexagon const &)。然而對於不同的形狀意味着不同的東西。

抽象基類(或不相關的同名方法)是另一種解決方案,但自由函數是用戶可擴展的,因此用戶在添加自己的內容後可以有效地獲得更統一的接口。

避免使用含糊不清的名稱的自由函數,以便不相關的函數不會成爲「競爭」覆蓋。

相關問題