2

Effective C++说“Prefer non-member non-frend functions to member functions”(第 23 条)。理由对我来说很有意义:它最小化了 API“表面积”。但在实践中,我经常发现很难说服人们(包括我自己)效仿。例如,假设我有一些形状类,它们应该支持周长和面积计算:

// @interface
class Shape {
 public:
  virtual double Area() = 0;
  virtual double Perimeter() = 0;
}

class Rectangle : public Shape {
 public:
  Rectangle(double width, double height);

  double width();
  double height();

  ...
};

class Circle : public Shape {
 public:
  Circle(double radius);

  double radius();
  ...
};

根据这个建议,似乎 Area 和 Perimeter 应该是非成员非朋友函数(而不是方法),因为它们可以。例如,可以通过 width 和 height 方法计算矩形的面积,如下所示:

double Area(const Rectangle& rectangle) {
  return rectangle.width() * rectangle.height();
}

事实上,Rectangle 和 Circle 都没有任何内部状态不会被它们的 getter 暴露出来,很难想象会是怎样的情况。因此,对这些进行操作的任何函数都不应该是方法。另一个例子:

// The diameter of a shape is the (circle) diameter of the smallest circle
// that contains a shape.
double Diameter(const Rectangle& rectangle) {
  double w = rectangle.width();
  double h = rectangle.height();
  return sqrt(w * w + h * h);
}

我在这里错过了什么吗?或者这实际上是个坏建议?

4

2 回答 2

5

如果您需要计算多态Shape对象的面积,那么 Scott 的建议不适合您的情况。因为您无法使用外部函数计算面积,因为实际上您没有公开访问所需信息的权限。即,对象实际上是圆形、矩形还是其他东西。所以这是虚拟功能的工作。

事实上,在 Scott 的确定函数正确放置的伪代码算法中(摘自这篇文章,因为我没有书),第一个测试是这样的:

if (f needs to be virtual)
    make f a member function of C;
于 2013-08-24T14:53:29.213 回答
0

如果你有一个类,其中的一些变量可以通过 getter 和 setter 直接访问,你有什么?对,无非就是struct一个“面向对象”的外观。绝对没有围绕使用这种数据容器的面向对象。

在我看来,面向对象的全部意义在于对行为建模,而不是对数据建模。在这方面,使用纯虚方法来计算面积和周长的抽象形状类是一个完全有效的设计:它从数据中抽象出来并公开您需要的行为。如果我是你,我会三思而后行为基本参数添加 getter(没有有用的抽象),三思而后行添加相应的 setter(打破封装)。

但是,无论如何,不​​要对拥有或不拥有访问器,或避免简单的普通旧数据结构,甚至是面向对象的设计过于执着。所有这些都有它的用途,并且为了避免它而避免它会在一种或另一种情况下导致糟糕的设计。我要说的是:想想什么最适合你的需要,然后完全无视一些大程序员提出的宗教规则。

于 2013-08-24T15:15:36.797 回答