34区分接口继承和实现继承
函数接口继承与函数实现继承,在public继承之下,derived classes总是继承base class的接口。
作为class的设计者:
1.有时我们希望derived classes只继承成员函数的接口(声明);
2.有时我们会希望derived classes同时继承函数的接口与实现,但是又希望能够覆写(override)它们所继承的实现;
3.有时我们希望derived classes同时继承函数的接口与实现,但是不允许覆写任何东西。
class Shape{
public:
virtual void draw() const = 0; //pure virtual
virtual void error(const std::string& msg); //impure virtual
int objectID() const; //non-virtual
};
class Rectangle :public Shape{....};
public继承导致的is-a关系,导致成员函数的接口总会被继承。
在基类中三种不同的函数声明方式:
1.声明一个pure virtual函数的目的是为了让derived classes只继承函数接口
2.声明impure virtual 函数的目的是为了让derived classes继承该函数的接口与缺省实现。
其接口表示每个class都必须支持一个“当遇上错误时可调用的函数”,但是每个class可自由的处理错误。如果某个class不想针对错误做出特殊行为,它可以退回到shape class提供的缺省错误行为。
3.如果成员函数是个non-virtual函数,意味着它并不打算在derived classes中有不同行为。声明non-virtual函数的目的是为了令derived classes继承函数的接口及一份强制性实现。
Shape::objectID的声明是让每个Shape对象都有一个用来产生对象识别码的函数,此识别码总是采用相同的计算方法,此方法
由Shape::objectID的定义式决定,任何派生类都不应该尝试改变其行为。
pure virtual函数、impure virtual 函数、non-virtual函数之间的差异,使得你得以精确指定你想要derived classes继承的东西:只继承接口、或是继承接口和一份缺省实现
、或是继承接口和一份强制实现。
经验不足的class设计者常会犯下以下两个错误:
virtual函数的成本:
一个典型的程序有%80的执行时间花费在%20的代码上,这个法则十分重要。
1.将所有的函数声明为non-virtual,这使得derived classes没有剩余的空间进行特化工作。这种是不变性凌驾于特异性
2.将所有的成员函数声明为virtual。例如接口类。 这种是特异性凌驾于不变性