继承
三种继承方式
不同的继承方式会影响基类成员在派生类中的访问权限。
public继承方式
- 1.基类中所有 public 成员在派生类中为 public 属性;
- 2.基类中所有 protected 成员在派生类中为 protected 属性;
- 3.基类中所有 private 成员在派生类中不能使用。
派生类可以访问基类的 public、protected 成员,不可以访问基类的 private 成员;派生类对象可以访问基类的public成员,不可以访问基类的protected、private成员。
protected继承方式
- 1.基类中的所有 public 成员在派生类中为 protected 属性;
- 2.基类中的所有 protected 成员在派生类中为 protected 属性;
- 3.基类中的所有 private 成员在派生类中不能使用。
派生类可以访问基类的 public、protected 成员,不可以访问基类的 private 成员;派生类对象不可以访问基类的 public、protected、private 成员。
重点
1.派生类从基类那里继承了什么?
- 基类的公有成员将成为派生类的公有成员,基类的私有对象也将成为派生类的一部分,但只能通过基类的公有和保护方法访问。
2.派生类不能从基类那里继承什么?
- 构造函数
- 赋值运算符
- 析构函数
- 友元
菱形继承
案例
// 间接基类A class A{ protected: int m_a; }; // 直接基类B class B: public A{ protected: int m_b; }; // 直接基类C class C: public A{ protected: int m_c; }; //派生类D class D: public B, public C{ public: void seta(int a) { //m_a = a; //命名冲突 A::m_a = a; //命名不再冲突 } void setb(int b){ m_b = b; //正确 } void setc(int c){ m_c = c; //正确 } void setd(int d){ m_d = d; //正确 } private: int m_d; }; int main(){ D d; return 0; }
虚继承
在 C++ 中,在使用 多继承 时,如果发生了 菱形继承,那么就会出现数据冗余的问题,为了解决菱形继承出现的数据冗余的问题,C++ 提出了虚继承,虚继承使得派生类中只保留一份间接基类的成员。
语法
class B: virtual public A{ //虚继承 };
案例
// 间接基类A class A{ protected: int m_a; }; // 直接基类B class B: virtual public A{ protected: int m_b; }; // 直接基类C class C: virtual public A{ protected: int m_c; }; //派生类D class D: public B, public C{ public: void seta(int a){ m_a = a; //正确 } void setb(int b){ m_b = b; //正确 } void setc(int c){ m_c = c; //正确 } void setd(int d){ m_d = d; //正确 } private: int m_d; };
虚继承构造函数
在 C++ 中,普通的 继承 时,可以在子类直接显式的调用父类的 构造函数,在 虚继承 中,虚基类是由最终的派生类初始化的。
也就是说,最终派生类的构造函数必须要调用虚基类的构造函数。对最终的派生类来说,虚基类是间接基类,而不是直接基类。这跟普通继承不同,在普通继承中,派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的。
// 间接基类A class A{ public: A(int a):m_a(a){} protected: int m_a; }; // 直接基类B class B: virtual public A{ public: B(int a, int b):A(a), m_b(b){} void display() { cout << "Call B m_a = " << m_a << ", m_b = " << m_b <<endl; } protected: int m_b; }; // 直接基类C class C: virtual public A{ public: C(int a, int c):A(a), m_c(c){} void display() { cout << "Call C m_a = " << m_a << ", m_c = " << m_c <<endl; } protected: int m_c; }; //派生类D class D: public B, public C{ public: // a最终会初始化为50,而不是90和100 D(int a, int b, int c, int d):A(a), B(90, b), C(100, c), m_d(d){} void display() { cout << "Call D m_a = " << m_a << ", m_b = " << m_b << ", m_c = " << m_c << ", m_d = " << m_d << endl; } void seta(int a){ m_a = a; //正确 } void setb(int b){ m_b = b; //正确 } void setc(int c){ m_c = c; //正确 } void setd(int d){ m_d = d; //正确 } private: int m_d; }; int main(){ B b(10, 20); b.display(); C c(30, 40); c.display(); D d(50, 60, 70, 80); d.display(); return 0; }