多重继承与派生类成员标识

单一继承

一个派生类只有一个直接基类的情况称为单一继承(single-inheritance)。

class Person // 人
{};
class Student: public Person // 学生
{};
class GStudent: public Student // 研究生
{};

多重继承或多继承

由多个基类共同派生出新的派生类,这样的继承结构被称为多重继承或多继承(multiple-inheritance)。
在继承树只有一层的情况下,多重继承几乎等同于按顺序单一继承了若干个类。
示例1: 派生类躺椅类继承了基类椅子和床类

class Chair // 椅子
{};
class Bed // 床
{};
// 躺椅
class DeckChair : public Bed, public Chair
{
};

菱形继承:

在继承树比较长的情况下,多重继承的情况会很复杂。 ,菱形继承是多继承的一种特殊情况。
示例:公共基类:person,派生类student继承person,GStudent继承student, 派生类 :EMployee 继承 preson
派生类 :EGStudent 继承了GStudent 和 EMployee
派生类对象的构造过程
在这里插入图片描述

class Person // 人
{
private:
int _idPerson;
public:
Person(int id) :_idPerson(id) { cout << "Create Person" << endl; }
};
class Student : public Person // 学生
{
private:
int _snum;
public:
Student(int s, int id) :Person(id), _snum(s) {}
};
class GStudent : public Student // 研究生
{
private:
int _gsnum;
public:
GStudent(int g, int s,int id) :Student(s,id),_gsnum(g) {}
};
// 教职工
class Employee : public Person
{
private:
int _enum;
public:
Employee(int e, int id) :Person(id), _enum(e) {}
};
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) {}
};
int main()
{
EGStudent egs(1, 2, 3, 4, 5, 6);
return 0;
}

数据冗余和二义性

两个身份证号从逻辑上讲应是一回事,但是物理上是分配了不同内存空间,是两个变量。
在这里插入图片描述
对象的内存分布图
在这里插入图片描述

虚基类:

数据冗余和二义性的解决办法:
两个身份证号显然是不合理的。可以把class Person这个共同基类设置为虚基类,这样从不同路径
继承来的同名数据成员在内存中就只有一个拷贝,同名函数也只有一种映射。
虚基类(virtual base class)定义方式如下:
class 派生类名:virtual 访问限定符 基类类名{…};
class 派生类名:访问限定符 virtual 基类类名{…};

virtual 关键字只对紧随其后的基类名起作用:

class Person // 人
{
private:
int _idPerson;
public:
Person(int id) :_idPerson(id) { cout << "Create Person" << endl; }
};
class Student : public virtual Person // 学生
{
private:
int _snum;
public:
Student(int s, int id) :Person(id), _snum(s) {}
};
class GStudent : public Student // 研究生
{
private:
int _gsnum;
public:
GStudent(int g, int s, int id) :Student(s, id), _gsnum(g),Person(id) {}
};
// 教职工
class Employee : public virtual Person
{
private:
int _enum;
public:
Employee(int e, int id) :Person(id), _enum(e) {}
};
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)
{
}
};
int main()
{
EGStudent egs(1, 2, 3, 4, 5);
Person *p = &egs;
return 0;
}

虚继承中派生类对象的构造过程:
在派生类对象的创建中,首先是虚基类的构造函数并按它们声明的顺序构造。第二批是非虚基类的构
造函数按它们声明的顺序调用。第三批是成员对象的构造函数。最后是派生类自己的构造函数被调用
菱形虚拟继承的egs对象的内存分布图:
在这里插入图片描述
物理内存:
在这里插入图片描述
总结:
有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂。所以一般不
建议设计出多继承,不要设计出菱形继承。否则在复杂度及性能上都有问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值