Effective C++ 总结[条款34 区分接口继承和实现继承]
在如下的继承体系中:
class Slime { public: virtual void spAttack() = 0; // pure virtual virtual void normalAttack(); // impure virtual void move(); // non-virtual protected: Slime(); virtual ~Slime(); private: int _hp; int _atk; float _speed; int _x; int _y; }; class FireSlime : public Slime { public: virtual void spAttack(); virtual void normalAttack(); }; class IceSlime : public Slime { public: virtual void spAttack(); virtual void normalAttack(); };
Slime是一个抽象类,因为它有一个纯虚函数spAttack,另外,还有一个非纯虚函数normalAttack和一个非虚函数move。FireSlime和IceSlime是继承于Slime的子类。
- 纯虚函数
父类中无须提供实现代码( 提供了也不报错,唯一的调用方式Slime::spAttack( ) );
子类必须提供实现代码,因为父类无法提供缺省实现(即子类不声明spAttack的话,不可用父类的实现,实际上编译都通不过);
这一类函数,子类只继承父类的函数接口。
// 一般是不要提供实现,除非你想给某个大师留下深刻印象:} void Slime::spAttack() { // do something } void FireSlime::spAttack() { // fire ball // well, we can use base class's default action, such as Slime::spAttack(); } void IceSlime::spAttack() { // ice ball, ice steam }
- 非纯虚函数
每个子类都可以重定义该函数的实现,如果不想重定义,可以用父类的缺省实现;
缺点:如果你忘记声明某个行为,但是客户使用了,它将表现出父类的缺省行为(这或许不是你想要的结果);
这一类函数,子类继承父类的函数接口和缺省实现。
class Slime { public: virtual void spAttack() = 0; virtual void normalAttack(); void move(); }; class IceSlime : public Slime { public: virtual void spAttack(); // virtual void normalAttack(); }; void Slime::normalAttack() { // hit } int main() { Slime* pIceSlime = new IceSlime; pIceSlime->normalAttack(); // maybe, I wantn't ice-slime do hit attack }
- 非虚函数
子类不可改变其内容,因此,父类在定义非虚函数时,应充分考虑是否适用于每个子类。
这一类函数,子类继承父类的函数接口和强制实现。
void Slime::move() { // move somewhere } int main() { Slime* pFireSlime = new FireSlime; Slime* pIceSlime = new IceSlime; pFireSlime->move();// do as same as base class pIceSlime->move();// do as same as base class }
综上,
- 只继承接口——纯虚函数,不须提供实现代码;
- 继承接口和缺省实现——非纯虚的虚函数;
- 继承接口和强制实现——非虚函数。

浙公网安备 33010602011771号