万能的函数 之 接口继承 实现继承~~~
2014-04-27 15:01
246 查看
在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只继承基类的成员函数的接口,有时候又需要同时继承函数的接口以及实现,有时候又需要重写(override)它们所继承的实现,有时候又希望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
来完成。例如下面的代码:
因此,使用 pure virtual + default action来改进,有:
现在新添加的SecC航线,就必须自己定义fly函数了。
值得注意的是:上面的defaultFly函数是non-virtual的,因为没有任何函数需要重新定义它~~
试想,如果 defaultFly 函数是virtual的,那么某些类忘记定义了怎么办,额~~好熟悉的话,又得循环回去了~~
注意,在上面提到过pure virtual函数也是可以有定义体的,那么我们就可以不用声明 defaultFly 函数了,实现接下来的部分:
最后,对于non-virtual的函数,很简单,derived class 不能重新定义,只能无条件的继承该函数的接口与实现。
综上所述:定义virtual (pure / impure)以及non-virtual 是取决于类的设计者的意图:
在public 继承下,derived class 总是继承base class的全部接口。
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只继承基类的成员函数的接口,有时候又需要同时继承函数的接口以及实现,有时候又需要重写(override)它们所继承的实现,有时候又希望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); } ... } ;
现在新添加的SecC航线,就必须自己定义fly函数了。
值得注意的是:上面的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函数 指定了继承接口以及一份强制的实现。
相关文章推荐
- 使用继承或接口实现模板方法的方式与函数回调的感悟
- COM接口继承IUnkonwn接口,关于IUnkonwn里面函数实现中用到引用计数的总结
- Net如何继承IDisposable接口,实现自己的Dispose()函数
- Effective C# 原则20:明辨接口实现和虚函数重载的区别
- 改进C#代码之24:通过定义并实现接口替代继承
- 继承:继承接口和实现
- 类不能继承接口,只能实现接口
- 创建线程的两种方式:继承Thread类和实现Runnable接口
- Java并发03:多线程实现三方式:继承Thread类、实现Runnable接口、实现Callable接口
- Java 继承接口同名函数问题
- 如何在linux C/C++语言中调用 sqlite 的函数接口来实现对数据库的管理(转)
- A:LinkedList实现了List接口; B: AbstractSet实现了Set接口; C: HashSet继承自AbstractSet基类; D: WeakMap继承自 AbstractMap
- java 接口 实现和继承关系
- 细说继承Thread类和实现Runnable接口来创建线程的区别
- JavaScript面向对象-基于函数伪造的方式实现继承
- 【07】面对对象3_继承,super,函数覆盖,子类实例化,final,抽象,接口
- Vector既然继承了AbstractList为啥还要实现List接口
- php利用接口实现类的多重继承
- java 接口 实现和继承关系
- Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?