万能的函数 之 接口继承 实现继承~~~
在public继承中,(public 继承表示的关系是 “is a ” 的关系),其类中定义的函数主要有三类:pure virtual函数,impure virtual函数以及non-virtual函数,这三种函数决定了public继承中的两个重要概念 : “ 函数接口继承” 以及 “函数实现继承”。那么接下来将针对这样一个不简单的问题做一些简介。
考虑如下的类定义:
class Shape{
public:
virtual void show() const = 0;
virtual void error(const string &) ;
int getID() const;
....
};
class Rectangular : public Shape { ... };
class Ellipse : public Shape { ... } ;
对于上述类,首先做一些简单的说明:
Shape是抽象类,因为其中含有纯虚函数( show函数 ), 抽象类不能定义对象,值得注意的是,虽然show函数是纯虚函数,但是并不表示Shape不可以为其定义函数体。Shape可以为show函数定义函数体,但是对该函数的调用显然不能由对象来调用(因为Shape不能定义对象),因此只能 Shape::show() ;来调用。
接下来,就是重要的部分了。
身为class的设计者,有时候希望derived class只继承基类的成员函数的接口,有时候又需要同时继承函数的接口以及实现,有时候又需要重写它们所继承的实现,有时候又希望derived同时继承接口与实现,并且不允许重写。
这些复杂的关系,接下来根据上述类的定义一步一步的解析:
Shape的成员函数的接口总是被继承。 由于 public 继承的 “is a ” 关系,也就是说任何可以施加到base class上的行为都可以施加到derived class身上。至于derived class如何使用他们,这便与 上述3种 virtual 函数有关。
首先,pure virtual 纯虚函数。 它必须被任何继承了它的class重新生命,并且定义,因为他们在抽象class类通常没有定义(只是通常,原因见上)。
1 声明pure virtual 函数 是为了让derived class继承它的接口(也没有函数体可以继承 啊~~)。只是告诉 derived class自行去去定义自己的实现。
2 声明impure virtual函数 是为了让derived class继承它的接口以及缺省实现(当然derived class也可以自己重新实现,多态~~)
但是,这样会遇到问题,如果新添加的derived class忘记定义自己的impure virtual函数体,也就意味着它直接使用base class的定义,这可能违背本身derived class的操作,造成意想不到的结果。对于这种问题,我们可以使用 pure virtual + default action来完成。例如下面的代码:
class Airplane { public: virtual void fly(string &destination); //虚函数,发出飞机飞行的目的地的指令 ... }; class SecA : public Airplane { ... } ; //SecA 与 SecB直接使用的base class的默认fly定义 class SecB : public Airplane { ... } ; //先新添加一条航线SecC,但是忘记定义了的fly函数指定目的地,因此C航线,依旧飞的是原来的路线,这恐怕不是你想要的吧。 class SecC : public Airplane {...};
因此,使用 pure virtual + default action来改进,有:
class Airplane { public: virtual void fly(string &destination) = 0; //纯虚函数,由各个航线自己指定目的地 ... protected: void defaultFly(const string &destination); }; void Airplane :: defaultFly (const string &destination)) { //default fly strategy } //SecA 与 SecB自行实现fly函数决定目的地。 class SecA : public Airplane { virtual void fly(string &destination) { Airplane::defaultFly(destination); } ... } ; class SecB : public Airplane { virtual void fly(string &destination) { Airplane::defaultFly(destination); } ... } ;
值得注意的是:上面的defaultFly函数是non-virtual的,因为没有任何函数需要重新定义它~~
试想,如果 defaultFly 函数是virtual的,那么某些类忘记定义了怎么办,额~~好熟悉的话,又得循环回去了~~
注意,在上面提到过pure virtual函数也是可以有定义体的,那么我们就可以不用声明 defaultFly 函数了,实现接下来的部分:
class Airplane { public: virtual void fly(string &destination) = 0; //纯虚函数,由各个航线自己指定目的地 ... }; void Airplane :: fly (string &destination)) { //default fly strategy } //SecA 与 SecB自行实现fly函数决定目的地。 class SecA : public Airplane { virtual void fly(string &destination) { Airplane::fly(destination); //通过类名调用纯虚函数的实现 } ... } ; class SecB : public Airplane { virtual void fly(string &destination) { Airplane::fly(destination); } ... } ;
最后,是那个non-virtual的函数,很简单,derived class 不能重新定义,只能无条件的继承该函数的接口与实现。
综上所述:定义virtual (pure / impure)以及non-virtual 是取决于类的设计者的意图:
在public 继承下,derived class 总是继承base class的全部接口。
pure virtual函数只指定了继承的接口。
impure virtual函数指定了继承接口以及一份缺省实现。
non-virtual函数则指定了继承接口以及一份强制的实现。