你的标题没有意义,你的解释有点模糊,所以让我们定义这些术语(并介绍关键的缺失术语)。
这里发生了两件不同的事情:
让我们从接口和抽象类开始。
- An 抽象类(在 C++ 中)是一个无法实例化的类,因为它的至少一个方法是纯虚方法。
- An 界面,在类似 Java 的语言中,是一组没有实现的方法,在 C++ 中它被模拟为抽象类仅使用纯虚方法。
因此,在 C++ 上下文中,两者之间没有太大区别。特别是因为这种区别从未考虑到自由函数。
例如,考虑以下“接口”:
class LessThanComparable {
public:
virtual ~LessThanComparable() {}
virtual bool less(LessThanComparable const& other) const = 0;
};
即使使用免费函数,您也可以轻松地增强它:
inline bool operator<(LessThanComparable const& left, LessThanComparable const& right) {
return left.less(right);
}
inline bool operator>(LessThanComparable const& left, LessThanComparable const& right) {
return right.less(left);
}
inline bool operator<=(LessThanComparable const& left, LessThanComparable const& right) {
return not right.less(left);
}
inline bool operator>=(LessThanComparable const& left, LessThanComparable const& right) {
return not left.less(right);
}
在这种情况下,我们提供行为......但类本身仍然是一个接口......哦,好吧。
因此,真正的争论在于遗产 and 作品.
继承经常被滥用来继承行为。这不好。应该使用继承来建模is-a关系。否则,您可能需要组合。
考虑简单的用例:
class DieselEngine { public: void start(); };
现在,我们如何构建一个Car
有了这个 ?
如果你继承的话,它会起作用。然而,突然你得到这样的代码:
void start(DieselEngine& e) { e.start(); }
int main() {
Car car;
start(car);
}
现在,如果您决定更换DieselEngine
with WaterEngine
,以上功能不起作用。编译失败。并且拥有WaterEngine
继承自DieselEngine
当然感觉很ikky...
那解决办法是什么?作品.
class Car {
public:
void start() { engine.start(); }
private:
DieselEngine engine;
};
这样,没有人可以编写无意义的代码来假设汽车是发动机(哦!)。因此,更换发动机是easy绝对与没有客户影响.
这意味着您的实现与使用它的代码之间的一致性较差;或通常所说的:更少的耦合.
经验法则是,一般来说,从具有数据或实现行为的类继承应该是不受欢迎的。它可以是合法的,但通常有更好的方法。当然,就像所有的经验法则一样,我们对此持保留态度。小心过度设计。