C++ :七、继承(2)

(一)多重继承

多重继承是指由多个基类共同派生出新的派生类的继承结构。这种继承方式能够让派生类融合多个基类的特性,为程序设计带来更大的灵活性。

例如,在描述交通工具的类体系中,我们可以定义FuelEngine类(燃油引擎)和ElectricEngine类(电动引擎):

class FuelEngine 
{
private:
    int cylinderNum; 
public:
    FuelEngine(int n = 4) :cylinderNum(n) {}
    void Start();  
};

class ElectricEngine 
{
private:
    int power; 
public:
    ElectricEngine(float p = 60):power(p) {}
    void Start();
};

接着,定义HybridCar类(混动汽车)同时继承这两个类,使其具备两种引擎的相关特性:

class HybridCar: public FuelEngine, public ElectricEngine
{
public:
    HybridCar() {}
    HybridCar(int n, int p){}
};

然而,多重继承虽然强大,但也引入了一些问题,如代码的复杂性增加、潜在的命名冲突等,需要开发者谨慎使用。

(二)菱形继承

菱形继承是多重继承的一种特殊情况。以人员信息管理的类设计为例,Person类作为基类,包含人员的基本信息,如身份证号:

class person 
{
private:
    int _idPerson;
public:
    person(int id) :_idPerson(id) { std::cout << "create person" << std::endl; }
};

student类(学生)和Employee类(教职工)都继承自Person类:

class student : public Person 
{
private:
    int _snum;
public:
    Student(int s, int id) :Person(id), _snum(s) {}
};

class Employee : public Person
{
private:
    int _enum;
public:
    Employee(int e, int id) :Person(id), _enum(e) {}
};

EGStudent类(在职研究生)又同时继承自student类和Employee类,形成了菱形继承结构:

class EGStudent : public GStudent, public Employee
{
private:
    int _egsnum;
public:
    EGStudent(int es, int g, int s, int sid, int e, int eid)
        :GStudent(g, s, sid),
        Employee(e, eid),
        _egsnum(es)
    {
    }
};

在这种结构中,EGStudent类会继承两份来自Person类的成员(如_idPerson),这就导致了数据冗余和二义性问题。从逻辑上讲,身份证号应该是唯一的,但在物理内存中却分配了不同的空间,变成了两个变量。

(四)虚基类

为了解决菱形继承带来的数据冗余和二义性问题,C++ 引入了虚基类的概念。通过将共同的基类(如Person类)设置为虚基类,从不同路径继承来的同名数据成员在内存中就只有一个拷贝,同名函数也只有一种映射。
定义虚基类的方式如下:

class student : public virtual Person  
{
private:
    int _snum;
public:
    Student(int s, int id) :Person(id), _snum(s) {}
};

class Employee : public virtual Person
{
private:
    int _enum;
public:
    Employee(int e, int id) :Person(id), _enum(e) {}
};

此时,EGStudent类的定义和构造函数如下:

class EGStudent : public GStudent, public Employee
{
private:
    int _egsnum;
public:
    EGStudent(int es, int g, int s, int id, int e)
        :GStudent(g, s, id),
        Employee(e, id),
        Person(id),
        _egsnum(es)
    {
    }
};

在虚继承中,派生类对象的构造过程也有所不同。首先是虚基类的构造函数按照声明顺序被调用,接着是非虚基类的构造函数按声明顺序调用,然后是成员对象的构造函数被调用,最后是派生类自己的构造函数被调用。

1.虚基类的底层实现原理

虚基类的底层实现原理主要依靠:虚基类表指针(VBPtr)和虚基类表(VBTbl),当一个类虚继承自某个基类时,编译器会为该派生类对象添加一个额外的指针,称为虚基类表指针(VBPtr)。这个指针指向一个虚基类表(VBTbl)。虚基类表中存储了该派生类对象相对于虚基类对象的偏移量信息。

(五)继承使用建议

虽然 C++ 提供了多重继承和虚基类等强大的机制,但由于菱形继承及其虚继承底层实现较为复杂,可能会导致程序的复杂性增加以及性能问题。

因此,在实际的软件开发中,一般不建议设计出多重继承结构,尤其是菱形继承结构,而是尽量采用更为简洁、清晰的设计方式,以提高代码的可读性、可维护性和性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值