您的位置:首页 > 编程语言 > C语言/C++

C++【多重继承和虚继承】

2015-06-16 12:02 281 查看
多重继承和虚继承

1)定义

子类同时拥有两个或两个以上的基类,同时继承了所有基类的属性和行为。

销售员 经理

\ /

销售经理

汽车 客用特性 商用特性

\ | /

公共汽车

2)内存结构

按照继承表的顺序,从低到高地址一次排列各个基类子对象。将子类对象的地址隐式或者静态转换为基类指针,编译器会做地址计算,以保证基类指针的类型和其所指向的对象一致,但是重解释类型转换(reinterpret_cast)不做此计算。

3)防止名字冲突

由用户程序通过作用域限定解决冲突,或者借助using声明以重载的方式解决冲突,再或者通过汇聚替代,在汇聚子类中提供对产生冲突的函数的隐藏版本,并在该隐藏版本中通过正确的逻辑选择特定基类的实现。

示例代码:

#include <iostream>
using namespace std;
class Phone {
public:
Phone (const string& numb) : m_numb (numb) {}
void call (const string& numb) const {
cout << m_numb << "打给" << numb << "。"
<< endl;
}
void foo (void) {
cout << "Phone::foo()" << endl;
}
void bar (void) {
cout << "Phone::bar()" << endl;
}
private:
string m_numb;
};
class Player {
public:
Player (const string& media) : m_media (media) {}
void play (const string& clip) const {
cout << m_media << "播放器播放" << clip
<< "。" << endl;
}
void foo (int n) {
cout << "Player::foo()" << endl;
}
void bar (void) {
cout << "Player::bar()" << endl;
}
private:
string m_media;
};
class Computer {
public:
Computer (const string& os) : m_os (os) {}
void run (const string& prog) const {
cout << "在" << m_os << "上运行" << prog
<< "。" << endl;
}
private:
string m_os;
};
class SmartPhone : public Phone, public Player,
public Computer {
public:
SmartPhone (const string& numb,
const string& media, const string& os) :
Phone (numb), Player (media), Computer (os) {}
using Phone::foo;//防止名字冲突,借助using声明以重载的方式解决冲突
using Player::foo;//防止名字冲突,借助using声明以重载的方式解决冲突
//  using Phone::bar;
//  using Player::bar;
void bar (bool flag) {
if (flag)
Phone::bar ();
else
Player::bar ();
}
};
int main (void) {
SmartPhone sp ("13910110072", "MP4", "iOS");
sp.call ("01062332018");
sp.play ("哈利波特");
sp.run ("QQ");
cout << &sp << endl;
Phone* p1 = &sp;//指向子类对象的基类指针
cout << p1 << endl;
Player* p2 = &sp;
cout << p2 << endl;
//  Computer* p3 = static_cast<Computer*> (&sp);//将子类对象的地址隐式或者静态转换为基类指针
Computer* p3 = reinterpret_cast<Computer*> (&sp);//但是重解释类型转换(reinterpret_cast)不做此计算
cout << p3 << endl;//0x7fff09aaabe0
/*
sp.Phone::foo ();//防止名字冲突由用户通过作用域限定解决冲突
sp.Player::foo (10);
*/
sp.foo ();
sp.foo (10);
sp.bar (true);
sp.bar (false);
return 0;
}
*输出结果*:
13910110072打给01062332018
MP4播放器播放哈利波特
在iOS上运行QQ
0x7fff09d33520
0x7fff09d33520
0x7fff09d33528
0x7fff09d33530
Phone::foo()
Player::foo()
Phone::bar()
Player::bar()


4)钻石继承问题

公共基类子对象在最终子类对象中存在多个实例,沿着不同的继承路径所访问到的公共基类子对象可能不一样,由此导致数据不一致问题。

A

/ \

B C

\ /

D

为了解决钻石继承问题,需要设法让公共基类子对象在最终子类对象中仅有唯一的实例,且为所有中间子类对象所共享——虚继承。

示例代码:

#include <iostream>
using namespace std;
class A {
public:
A (int data) : m_data (data) {
cout << "A:" << this << endl;
}
protected:
int m_data;
};
class B : virtual public A {
public:
B (int data) : A (data) {
cout << "B:" << this << endl;
}
void set (int data) {
m_data = data;
}
};
class C : virtual public A {
public:
C (int data) : A (data) {
cout << "C:" << this << endl;
}
int get (void) {
return m_data;
}
};
class D : public B, public C {
public:
D (int data) : B (-1), C (-2), A (data) {
cout << "D:" << this << endl;
}
};
int main (void) {
D d (100);
cout << d.get () << endl;//100
d.set (200);
cout << d.get () << endl;//200
return 0;
}
输出结果:
A:0x7fff86fbd060
B:0x7fff86fbd050
C:0x7fff86fbd058
D:0x7fff86fbd050
100
200
分析:
调用构造函数,基类-(成员)-子类,如果多个子类,根据继承顺序表决定构造顺序,this是指针,返回地址
内存结构,按照继承表的顺序,从低到高地址一次排列各个基类子对象
基类构造函数先A再B后C
子类构造函数D
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: