1. 多重继承
1.1 多重继承
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/74c4539f54a718aea9287bdb166a0b7c.png)
#include <iostream>
#include <cstring>
using namespace std;
class Phone{
public:
Phone(const string& num):m_num(num){}
void call(const string& num){
cout << m_num << "打给" << num << endl;
}
private:
string m_num;
};
class Player{
public:
Player(const string& media):m_media(media){}
void play(const string& music){
cout << m_media << "播放" << music << endl;
}
private:
string m_media;
};
class Computer{
public:
Computer(const string& os):m_os(os){}
void run(const string& app){
cout << "在" << m_os << "系统运行" << app << endl;
}
private:
string m_os;
};
class SmartPhone:public Phone, public Player, public Computer{
public:
SmartPhone(const string& num, const string& media, const string& os):
Phone(num), Player(media), Computer(os){};
};
int main(void){
SmartPhone xiaomi("123456789", "Mp4", "Android");
xiaomi.call("987654321");
xiaomi.play("<<晴天>>");
xiaomi.run("消消乐");
SmartPhone* p1 = &xiaomi;
Phone* p2 = p1;
Player* p3 = p1;
Computer* p4 = p1;
cout << "p1:" << p1 << endl;
cout << "p2:" << p2 << endl;
cout << "p3:" << p3 << endl;
cout << "p4:" << p4 << endl;
}
$ ./a.out
123456789打给987654321
Mp4播放<<晴天>>
在Android系统运行消消乐
p1:0x7ffd81b67a00
p2:0x7ffd81b67a00
p3:0x7ffd81b67a20
p4:0x7ffd81b67a40
1.2 多重继承的向上造型
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/8d46dc4234df958bd76d50ec38f17ade.png)
- SmartPhone类所创建的子对象分别包含3个基类子对象,Phone,Player, Computer。这3个基类子对象内存是连续的(按照继承表的继承顺序)。
- 每个子对象里面包含一个string类型的成员变量,在当前系统环境下string类型占24个字节。
- p1 是 SmartPhone* 类型,指向的内存包含3个基类子对象,p2 指向的内存只包含Phone子对象, 并且和p1开头重合。p3将偏移24个字节,指向包含Player子对象的那块内存。同理p4。
- 偏移是为了保证,内存数据和指针类型的一致性, 不然会有逻辑错误。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/00bbed2cf60b249b4da28cedd9ce7d44.png)
2. 名字冲突问题
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/5e87f70b347570e374d8f5382644fc99.png)
#include <iostream>
using namespace std;
class Base1{
public:
void func(void){
cout << "Base1::func(void)" << endl;
}
};
class Base2{
public:
void func(int a){
cout << "Base2::func(int)" << endl;
}
};
class Derived:public Base1, public Base2{
public:
};
int main(void){
Derived d;
d.Base1::func();
d.Base2::func(123);
}
$ ./a.out
Base1::func(void)
Base2::func(int)
3. 钻石继承和虚继承
3.1 钻石继承
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/3d96558483ae7f3ccf2099d17b07abe8.png)
#include <iostream>
using namespace std;
class A{
public:
A(int data):m_data(data){}
protected:
int m_data;
};
class B:public A{
public:
B(int data):A(data){}
void set(int data){
m_data = data;
}
};
class C:public A{
public:
C(int data):A(data){}
int get(void){
return m_data;
}
};
class D:public B, public C{
public:
D(int data):B(data), C(data){}
};
int main(void){
D d(100);
cout << d.get() << endl;
d.set(200);
cout << d.get() << endl;
}
$ ./a.out
100
100
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ff6ef67d09e3c17429017863ae6dde3e.png)
3.1 虚继承(vitrural 修饰继承表)
- 上面的问题可以同过虚继承解决, 让公共基类子对象只存在一份, 并且被所有中间类所共享。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/fb022023d214ed221bf56cb64a87287b.png)
- 虚继承语法
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/673733546b8082739ce9134f496081dd.png)
- virtual 对中间类是没有影响的。只会影响末端子类D对象。
#include <iostream>
using namespace std;
class A{
public:
A(int data):m_data(data){}
protected:
int m_data;
};
class B:virtual public A{
public:
B(int data):A(data){}
void set(int data){
m_data = data;
}
};
class C:virtual public A{
public:
C(int data):A(data){}
int get(void){
return m_data;
}
};
class D:public B, public C{
public:
D(int data):B(data), C(data), A(data){}
};
int main(void){
D d(100);
cout << d.get() << endl;
d.set(200);
cout << d.get() << endl;
}
$ ./a.out
100
200