C++浅谈组合和继承

来源:互联网 发布:一个网站几个域名 编辑:程序博客网 时间:2024/06/05 11:51

C++有三大特性:封装、继承和多态。

之前提到过继承是为了实现代码的复用,如果子类继承了父类那么就会继承父类所有的数据成员及成员函数,在公有继承的时候保持is-a原则,即每个子类的对象也是父类对象。

因此引入了单继承、多继承以及菱形继承等方式。但是正是因为继承太有用、太容易用、很容易实现代码的复用性因此我们需要选择性的继承。
如果A类和B类毫无关系,我们不应该为了让B类多一个功能而去让B继承A。
如果在逻辑上B是A的一种,即B类的man也是A类的 Hunman的一种我们就可以让B类去继承A类。
看以下例子:
#include<iostream>#include<stdio.h>using namespace std;class Eye{public:void Look(void){cout << "hello" << endl;}};class Nose{public:void Smell(void){cout << "Smell()" << endl;}};class Mouth{public:void Eat(void){cout << "Eat()" << endl;}};class Ear{public:void Listen(void){cout << "Listen" << endl;}};class Head:public Eye,public Nose,public Mouth,public Ear{;};int main(){Head man;man.Eat();system("pause");return 0;}
这种采用继承的方法来实现Head类虽然代码简单并且运行结果也是正确的,但是它并不是一个高质量的程序,因为从上述例子我们可以看出Eye,Nose,Mouth,Ear这些类都是Head类的一部分(is -a-part-of)而不是(is -a-kind-of)的关系,他不能说成头部是眼睛、或者头部是鼻子,在逻辑上不符合在逻辑上B是A的一种。因此这种设计思想是有问题的。
我们可以通过组合来实现:
#include<iostream>#include<stdio.h>using namespace std;class Eye{public:void Look(void){cout << "hello" << endl;}};class Nose{public:void Smell(void){cout << "Nose()" << endl;}};class Mouth{public:void Eat(void){cout << "Eat()" << endl;}};class Ear{public:void Listen(void){cout << "Listen()" << endl;}};class Head{public:void Look(void){m_eye.Look();}void Smell(void){m_nose.Smell();}void Eat(void){m_mouth.Eat();}void Listen(void){m_ear.Listen();}private:Eye m_eye;Nose m_nose;Mouth m_mouth;Ear m_ear;};int main(){Head man;man.Look();system("pause");return 0;}
组合也是类的一种复用技术它遵循的就是如果A类是B类的一部分,则不要让B类去继承A类,而是采用组合的形式。
对比以上两个程序我们可以总结出组合和继承各自的优缺点:
组合
     优点:不会破环封装性父类的任何变化不会引起子类的变化
               组合运用复杂的设计他们的关系实在程序运行的时候才确定的可以支持动态的组合
               整体类可以对局部类的接口进行封装,提供新的接口

     缺点:整体类不能自动获得和局部类同样的接口,只有通过创建局部的对象去调用它
              创建整体类的时候需要创建局部类的对象
继承
    优点:子类继承了父类能自动获得父类的接口
              创建子类对象的时候不用创建父类对象

    缺点:破坏了封装,父类的改变必定引起子类的改变,子类缺乏独立性
              支持功能上的扩展,但多重继承往往增加了系统结构的复杂度。
              继承是在静态编译的时候就已经确定了关系,不支持动态继承。
因此优先考虑使用组合而不是继承。
              
    
      


1 0
原创粉丝点击