2010-04-06 56 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 &)。然而对于不同的形状意味着不同的东西。

抽象基类(或不相关的同名方法)是另一种解决方案,但自由函数是用户可扩展的,因此用户在添加自己的内容后可以有效地获得更统一的接口。

避免使用含糊不清的名称的自由函数,以便不相关的函数不会成为“竞争”覆盖。

相关问题