前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++:继承#2与组合

C++:继承#2与组合

作者头像
字节星球Henry
发布2021-08-09 16:48:32
2990
发布2021-08-09 16:48:32
举报

组合

类以另一个类对象作为数据成员的操作,称为组合,当两个类具有包含关系的时候,组合就比继承更能满足我们的要求,在思考如何选择组合与继承的时候,就应该分析两个类之间的关系,组合的实现方式如以下代码片段

代码语言:javascript
复制
class vehicle{
    //..
};
class engine{
    //..
};
class car:public vehicle{//public继承vehicle类
    public:
        engine eng;//与engine类对象组合
};
void vehicleFn(vehicle& v);
void engineFn(engine& e);
int main()
{
    car c;
    vehicleFn(c);//ok,car类是vehicle的继承
    engine(c);//error,参数要求是engine类对象的引用,对象c属于car类,car类并没有继承engine类,仅仅是与engine类对象组合
    engine(c.eng);//ok,eng是engine类对象
    return 0;
}

继承#2

多继承的模糊性

当一个类继承多个类的时候,如何有两个或以上的类具有同名的数据成员或成员函数,那么将会出现模糊性问题,访问成员时,究竟应该访问哪一个类的成员?

代码语言:javascript
复制
class gamePlayer{
    public:
        setWeight(int i){weight=i;}
    private:
        weight;
        //..
};
class tool{
    public:
        setWeight(int i){weight=i;}
    private:
        weight;
        //..
}:
class computer:public gamePlayer,public tool{
    public:
        //..
};
int main()
{
    computer com;
    com.setWeight(20);//setWeight()操作的是gamePlayer还是tool的weight???
    return 0;
}

以上操作导致了名称冲突(name collision),编译器禁止。

代码语言:javascript
复制
int main()
{
    computer com;
    com.gamePlayer.setWeight(20);//ok,对gamePlayer的weight操作
    return 0;
}
虚拟继承

以上案例中,computer(电脑)可以作为游戏机(gamePlayer)也可以作为工具(tool)来使用,所以我们将 computer 类继承于 gamePlayer 和 tool 类,但一台计算机只会存在一个质量,并不存在 gamePlayer 和 tool 两种质量,如果使用传统继承,会是以下情况:

代码语言:javascript
复制
class Electronics{
    //..
    protected:
        weight;
};
class tool:public Electronics{//计算机作为工具属于电子产品
    //..
};

class gamePlayer:public Electronics{//计算机作为游戏设备属于电子产品
    //..
};
class computer:public gamePlayer,public tool{
    //..
};

computer 继承于 gamePlayer 和 tool,而 gamePlayer 和 tool 又都继承于 Electronics,故 computer 包含一个完整的 gamePlayer 和 tool,而 computer 的子对象 分别都有自己的 Electronics 部分,导致 一个 computer 包含两个 Electronics,这又会导致模糊性产生,计算机并不清楚你的操作是针对于哪一个 Electronics,我们只希望有一个 Electronics 拷贝,同时又要共享 gamePlayer 和 tool 的成员,C++ 将实现这种继承结构的方法成为虚拟继承(virtual inheritance)

实现方法很简单,只需要在 gamePlayer 和 tool 继承 Electronics 中加上 virtual 关键字。

此操作会判断是否存在 Electronics 类,如果有,则使用现有的,如果没有则创建一个拷贝。

有了虚拟继承,之前存在的模糊性将不再模糊,因为始终只存在一个 Electronics。

多继承的构造顺序

按从上到下的顺序进行构造:

  1. 虚拟基类的构造函数按照被继承的顺序进行构造;
  2. 非虚拟基类的构造函数按照被继承的顺序进行构造;
  3. 成员对象(组合)的构造函数按照声明顺序进行构造;
  4. 类本身的构造函数;

如以下代码片段

代码语言:javascript
复制
class obj1{
    public:
        obj1(){cout<<"obj1"<<endl;}
};
class obj2{
    public:
        obj2(){cout<<"obj2"<<endl;}
};
class b1{
    public:
        b1(){cout<<"b1"<<endl;}
};
class b2{
    public:
        b2(){cout<<"b2"<<endl;}
};
class b3{
    public:
        b3(){cout<<"b3"<<endl;}
};
class b4{
    public:
        b4(){cout<<"b4"<<endl;}
};
class derived:public b1,virtual public b2,public b3,virtual public b4{
    public:
        derived():b2(),b4(),b1(),b3(),a(),b(){
            cout<<"it's ok"<<endl;
}
    protected:
        obj1 a;
        obj2 b;
};
int main()
{
    derived test;
    cout<<"main function ok"<<endl;
    return 0;
}

运行结果:

代码语言:javascript
复制
b2
b4
b1
b3
obj1
obj2
it's ok
main function ok

虚拟继承的 b2,b4 首先构造,普通继承的 b1,b3 随后,作为数据成员的对象再构造,最后是 derived 类本身的构造函数。


编辑:Henry 2021-03-08 未授权禁止转载

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 组合
  • 继承#2
    • 多继承的模糊性
      • 虚拟继承
        • 多继承的构造顺序
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档