使用类继承还是类的成员变量

对于继承和成员变量有很多相似的地方,那么何时用继续,何时用成员变量呢。是不是都用继承好呢?

 

比如有个class A 和 class B
我在B里面定义一个A类型成员 a;
class B
{
...
A a;
...
};

或者把A作为B的父类
class B : public A
{
};
又有个 B b;
要用a的时候两种方法都可以通过 b.a 来做到。
那么继承的优点都体现在哪呢?

 

其实它们非常像,但是还是有些区别:

1 对于protected的成员变量的访问
比如我要在B中访问类A的一个成员变量m,通过继承的方式只要在类A中把m声明成protected,如果是包含的话,需要在类A中实现一个成员函数GetM返回m的值,如果要修改它的值同样又要实现一个SetM成员函数
如果B还有子类,B的子类要访问类A的成员变量,用包含的方式就更麻烦了。

2 对于容器里存放类

B继承A,表明B也是A的一种。
那么B同时具备了A的所有virtual接口。
举例:这时候A和B就可以混放到某个容器里。比如std::vector<A>。
这里面可以放A,也可以放B,然后再比如你for这个vector的时候就可以call到对应的virtual接口而不再需要类型判定。所谓多态(运行期)就是如此,面向接口的编程, Interface Oriented Programming。

至于B包含了A的做法,表明是:B使用了A。
就好比汽车有轮子,但汽车并不是轮子。
这时候std::vector<A>显然不能再放B了,因为性质完全不同。

绝大多数复杂业务的软件是两者都要同时使用的,对于继承则多数是继承接口(virtual xxxx = 0;)
而不是继承其实现。

此外,还有除了运行时动态多态,还有静态多态,多数时候用模板实现。
多态并不是一个语言强相关概念,而是一个抽象概念,用于描述业务对象之间的共性等复杂关系。

 

3 继承显示多态的特性

继承使得多态变成可能,让基类的指针或引用绑定派生类,也就是如果B C D都有继承A的的话,就可以A* ptrA=&B 或A* ptrA=&C之类去用基类指针指向派生类。这样的好处是可以用同一份代码去访问A拥有的接口。


而且如果A类有虚函数给B C D去重载的话,这样用A*去访问B C D中A部分的接口就可以实现“一个接口,多种策略”。因为用基类指针去这么访问接口用哪个版本,取决于这个指针绑定的对象。

 

比如数据库操作,可以定义的一个基类或者接口类,提供给访问数据库的程序调用,但是他们并不用关心内部是如何实现的。而具体的数据库可以通过特定的继承类来实现。

 

4 继承的优点是
1)扩大类的使用范围,更便于使用类库。
2)避免重写程序代码,提供有用的概念框架。
3把类转化成有条理的层次结构。

 

5 如何选择和使用继承

我们两种方式的区别和继承的优点,那么何时用成员变量,何时用继承呢。

个人觉得:

1)基础的功能类,比如字符串操作类,文件处理类等功能比较单一的基础类,建议直接使用成员变量。

2)有明显的包含关系,比如说B类就是A类的一个具体的实现,用继承。

3)需要对外部提供使用接口,不管是虚函数,还是接口函数,使用继承,方便扩展和使用。

 

6 本文仅从使用的方面做了简单的建议,还可以从类的构造和析构顺序,存储空间,生命周期等方面进行选择。

相关文章
相关标签/搜索