C++【多重继承和虚继承】
来源:互联网 发布:linux挂载磁盘阵列 编辑:程序博客网 时间:2024/04/28 06:35
多重继承和虚继承
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打给01062332018MP4播放器播放哈利波特在iOS上运行QQ0x7fff09d335200x7fff09d335200x7fff09d335280x7fff09d33530Phone::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:0x7fff86fbd060B:0x7fff86fbd050C:0x7fff86fbd058D:0x7fff86fbd050100200分析:调用构造函数,基类-(成员)-子类,如果多个子类,根据继承顺序表决定构造顺序,this是指针,返回地址 内存结构,按照继承表的顺序,从低到高地址一次排列各个基类子对象基类构造函数先A再B后C子类构造函数D
1 0
- C++【多重继承和虚继承】
- 多重继承和虚继承
- 多重继承和虚继承
- 多重继承、钻石继承和虚继承
- 多重继承,钻石继承和虚继承
- 多重继承和虚函数
- C++ 深入理解 虚继承、多重继承和直接继承
- C++ 深入理解 虚继承、多重继承和直接继承
- C++ 深入理解 虚继承、多重继承和直接继承
- C++ 深入理解 虚继承、多重继承和直接继承
- C++-继承:多重继承 && 虚拟继承
- 多重继承和虚拟继承
- 多继承和多重继承
- (C++)多重继承
- C++--多重继承
- 多重继承与虚继承
- 多重继承与虚继承
- 多重继承与虚继承
- Android开发组件安全维护
- VMware Workstation虚拟网卡Vmnet0,1,8之间的关系
- IOS中显示和隐藏状态栏的网络活动标志
- HTML 5 服务器发送事件
- uiscrollview uicollectionview touch事件传递问题
- C++【多重继承和虚继承】
- COM/DCOM开发之远程进程外组件(DCOM)
- hadoop集群的搭建脚本及构思(一):用户和用户权限
- Android 图片OutOfMemory异常bitmap size exceeds VM budget的原因及解决方法
- Java 继承详解
- Android ImageCache图片缓存
- HttpClient的CircularRedirectException异常原因及解决办法
- lamda 多表查询处理为空
- 设置背景图时防止图片拉伸的解决方法