C++多重继承
多重继承:
一个子类继承了多个基类
#include<iostream> #include<string> class Phone { public: Phone(const std::string& num) :m_num(num) { } void call(const std::string& num) { std::cout << "拨打号码:" << num << std::endl; } private: std::string m_num; }; class Player { public: Player(const std::string& med) :m_med(med) {} void plar(const std::string& music) { std::cout << "正在播放:" << music << std::endl; } private: std::string m_med; }; class Comp { public: Comp(const std::string& os) :m_os(os) {} void run(const std::string& app) { std::cout << m_os << "系统上运行:" << app << std::endl; } private: std::string m_os; }; class Smartphoto :public Phone, public Player, public Comp { //子类,继承了3个基类--多重继承 public: Smartphoto(const std::string& num, const std::string& med, const std::string& os) :Phone(num), Player(med), Comp(os) {}//初始化函数 //要调用各个基类的初始化函数 }; int main() { Smartphoto iphoto12("13116141117", "mp3", "windows"); iphoto12.call("13116140005"); iphoto12.plar("我的中国心"); iphoto12.run("王者荣耀"); Smartphoto* p = &iphoto12; Phone* p1 = p;//向上造型;p1=p,子类地址就是第一个基类的地址 Player* p2 = p; Comp* p3 = p; std::cout << sizeof(std::string) << std::endl; //不同系统大小可能不一样 std::cout << "p=" << p << std::endl; std::cout << "p1=" << p1 << std::endl; std::cout << "p2=" << p2 << std::endl; std::cout << "p3=" << p3 << std::endl; //各指针指向各自子对象的首地址 return 0; }
重点掌握:
运行输出内容:
28是string类型占用的字节数(不同系统大小可能不一样)
第一子对象的地址就是子对象的地址
第二子对象与第一子对象的间隔就是第一子对象所有成员变量占用字节数的总和
第三子对象与第二子对象的间隔就是第二子对象所有成员变量占用字节数的总和
名字冲突问题
解决方法一
#include<iostream> #include<string> class A { public: void func(void) { std::cout << "A的func函数" << std::endl; } }; class AA { public: void func(int i) { std::cout << "AA的func函数" << std::endl; } }; class B:public A, public AA { public: }; int main() { B b; //b.func(); //报错--不明确 //原因:继承了两个func函数,不明确调用哪个 b.A::func(); //加上类作用域 return 0; }
解决方法二
#include<iostream> #include<string> class A { public: void func(void) { std::cout << "A的func函数" << std::endl; } }; class AA { public: void func(int i) { std::cout << "AA的func函数" << std::endl; } }; class B:public A, public AA { public: using A::func; using AA::func;//声明基类函数的作用域到当前类 //两个函数构成了重载关系 }; int main() { B b; b.func(); b.func(100); return 0; }
钻石继承
继承关系图:
这种继承关系叫钻石继承
#include<iostream> #include<string> /* 钻石继承 A 公共基类 / \ B C 中间类 \ / D 末端子类 */ class A { public: A(int data):m_data(data){ std::cout << "A的指针:" << this << ",size=" << sizeof(A) << std::endl; } protected: int m_data; }; class B:public A { public: B(int data):A(data){ std::cout << "B的指针:" << this << ",size=" << sizeof(B) << std::endl; } void set(int newdata) { m_data = newdata; } }; class C:public A { public: C(int data) :A(data) { std::cout << "C的指针:" << this << ",size=" << sizeof(C) << std::endl; } int get(void) { return m_data; } }; class D :public B, public C { public: D(int data):B(data),C(data){ std::cout << "D的指针:" << this << ",size=" << sizeof(D) << std::endl; } }; int main() { D d(100); std::cout << d.get() << std::endl; //100 d.set(200); std::cout << d.get() << std::endl; //100 这个值没有被修改 //原因:看下面的理解图 return 0; }
理解图:
在创建末端子类(D)对象时,会包含多个公共基类(A)子对象,通过末端子类去访问公共基类的成员,会因为继承路径不同,而导致结果不一致
虚继承
【虚继承目的:为了共享公共基类的成员变量】
通过虚继承,可以让公共基类(A)子对象在末端子类(D)对象中实例唯一,为所有中间类共享,这样即使沿着不同继承路径所访问的成员一定是一致的
#include<iostream> #include<string> /* 钻石继承 A 公共基类 / \ B C 中间类 \ / D 末端子类 */ class A { public: A(short int data):m_data(data){ std::cout << "A的指针:" << this << ",size=" << sizeof(A) << std::endl; } protected: short int m_data; }; class B:virtual public A { //virtual 虚继承 public: B(short int data):A(data){ std::cout << "B的指针:" << this << ",size=" << sizeof(B) << std::endl; } void set(short int newdata) { m_data = newdata; } }; class C:virtual public A { //virtual 虚继承 public: C(short int data) :A(data) { std::cout << "C的指针:" << this << ",size=" << sizeof(C) << std::endl; } short int get(void) { return m_data; } }; class D :public B, public C { public: //虚继承时,由末端子类负责构造公共基类子对象 D(short int data):B(data),C(data),A(data){ std::cout << "D的指针:" << this << ",size=" << sizeof(D) << std::endl; } }; int main() { D d(100); std::cout << d.get() << std::endl; //100 d.set(200); std::cout << d.get() << std::endl; //200 return 0; }
虚继承语法:在中间类添加虚继承;在末端子类实现基类构造
在虚继承中,基类也叫虚基类
【个人理解:基类中的成员变量在各个虚继承的子类中是共享的】
虚继承类型大小的理解---了解
上面代码的返回值
A类大小=2,因为short int类型占2个直接
B类大小实际占用4个字节(就是虚表指针的大小),但是返回值是虚表指针大小+A类大小=6
C类大小跟B类大小一样
D类大小是两个虚表指针大小+A类大小=10