Effective C++说“首选非成员非frend函数到成员函数”(第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应该是非成员非朋友函数(不是方法),因为它们可以。例如。可以从宽度和高度方法计算矩形区域,如下所示:
double Area(const Rectangle& rectangle) {
return rectangle.width() * rectangle.height();
}
事实上,Rectangle和Circle都没有任何内部状态,它们的吸气剂都没有暴露,而且很难想象会是怎样的。因此,对这些操作的任何函数都不应该是一种方法。另一个例子:
// 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);
}
我在这里遗漏了什么吗?或者这实际上是不好的建议??
答案 0 :(得分:5)
如果你需要计算多态Shape
对象的面积,那么斯科特的建议不适合你的情况。因为您无法使用外部函数计算区域,因为实际上您无法公开访问所需的信息。即,对象实际上是圆形,矩形还是其他东西。所以这是虚拟功能的工作。
事实上,在Scott的psuedo-code算法中,用于确定函数的正确放置(取自this article,因为我没有这本书),第一个测试就是:
if (f needs to be virtual)
make f a member function of C;
答案 1 :(得分:0)
如果你的课程有一些可以通过getter和setter直接访问的变量,你有什么?是的,没有多于或少于struct
具有“面向对象”的外观。对于使用这样的 data 容器,绝对没有任何面向对象。
关于面向对象的全部观点,正如我所说,是模拟行为,而不是数据。在这方面,使用纯虚方法计算面积和周长的抽象形状类是一种完全有效的设计:它从数据中抽象出来并暴露您需要的行为。如果我是你,我会考虑为基本参数添加getter(没有有用的抽象),并且添加相应的setter三次(打破封装)。
但是,无论如何,不要因为拥有访问者,或者没有访问者,或者避免简单的旧数据结构,甚至是面向对象的设计而抱怨。所有这些都有它的用途,并且为了避免它而避免它会导致在一种或另一种情况下设计不良。我所说的只是:思考什么最适合你的需求,然后完全无视一些大程序员提出的宗教规则。