C++ 是支持多继承的语言,但是实际项目开发中非必要请避免使用多继承以降低代码逻辑的复杂性。
当然 C++ 多继承的特性带来一些问题即菱形继承。
当一个类继承了两个来自同父类的子类后,会产生命名空间冲突及资源冗余。
【伪代码】
class Base{
public:
int gem = 0;
};
class Byte : public Base{};
class Expert : public Base{};
class Blu : public Byte, public Expert{
public:
// Error 字段不明确
void SetGem(int i) {
this->gem = i;
}
}
可以看到,产生错误的主要原因是,Byte 和 Expert 同样都继承了 Base,然后 Blu 又继承了 Byte 和 Expert 。
根据 C++ 类继承的机制,子类的大小=父类大小+子类自身成员大小。
因此,可以看出,实际上 Blu 类当中存在两个 Gem 成员变量,分别来自 Byte 和 Expert,使用 this 指针进行调用,会发生命名空间冲突错误,同时造成了资源的重复浪费。
解决的方法也很简单,使用虚继承的方式:
【伪代码】
class Base{};
class Byte : virtual public Base{};
class Expert : virtual public Base{};
可以看到,在 Byte 和 Expert 的继承后面使用了 virtual 关键字进行了修饰。
这时,Base 便成了 Byte 和 Expert 的虚基类,达成了虚继承的方式,Base 类在最终的 Blu 类中只存在一个,所以不存在命名空间冲突及资源浪费。
虚基类并不是“绝对的”,而是“相对的”:虚基类在它自身声明、定义的时候无需任何修饰,只是在子类继承时进行 virtual 修饰。
然而这又牵扯到了另一种错误:
【伪代码】
class Base{};
class Byte : virtual public Base{};
class Expert : virtual public Base{};
class Frog : public Base{};
class Blu : public Byte, public Expert, public Frog{};
可以看到,Blu 继承了 Byte 、Expert、Frog 三个类,但是 Frog 类不是以虚继承的方式继承 Base 的。
所以在 Blu 类中仍然存在菱形继承的问题,所有需要将所有继承同一基类的上级父类继承方式声明为 virtual。
同时,在虚继承机制当中,虚基类是由最终的派生类进行初始化的,本身达成了一种 “间接继承” 的关系。
也就意味着最终的派生类在构造函数初始化中,要在初始化表中调用虚基类的构造函数进行初始化。
这样,就保证了虚基类不会被二次初始化。
最终正确代码是这样的:
class Base {
public:
Base() {};
~Base() {};
public:
int gem = 1;
};
class Byte : virtual public Base
{
public:
Byte() {};
~Byte() {};
};
class Expert : virtual public Base
{
public:
Expert() {};
~Expert() {};
};
class Blu : public Byte, public Expert
{
public:
// 调用虚基类构造函数
Blu() : Base(),Byte(),Expert() {};
~Blu() {};
void SetGem(int i) {
this->gem = i;
}
};
附:C++ 类继承权限参考表
public 公有成员 :基类、派生类、友元、外部都可以访问
protected 保护成员: 基类、派生类、友元可以访问
private 私有成员 :基类、友元可以访问
继承方式 | 基类 public 成员 | 基类 protected 成员 | 基类 private 成员 |
---|---|---|---|
public | public | protected | private |
protected | protected | protected | private |
privat | privat | private | private |
另外,虚继承概念:【Example】C++ 虚基类与虚继承 (菱形继承问题)
虚继承时,子类的内存结构当中不包含父类。
====================================
芯片烤电池 C++ Example 2022-Spring Season Pass :
【Example】C++ 回调函数及 std::function 与 std::bind
【Example】C++ 标准库智能指针 unique_ptr 与 shared_ptr
【Example】C++ Template (模板)概念讲解及编译避坑
【Example】C++ 标准库 std::thread 与 std::mutex
【Example】C++ 标准库多线程同步及数据共享 (std::future 与 std::promise)
【Example】C++ 标准库 std::condition_variable
【Example】C++ 用于编译时封装的 Pimpl 演示 (编译防火墙 Private-IMPL)
【Example】C++ 单例模式 演示代码 (被动模式、兼容VS2022编译)
====================================
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有