Skip to content

ch14 inheritance

本部分主要讲解 cpp 的继承机制,从单继承到多继承,实际上多继承和单继承一样,只要去解决名称的冲突就行了。

类成员的访问级别和类层次的访问修饰符

类成员的访问修饰符是指加在类成员面前的访问修饰符,类层次的访问修饰符是在继承的时候加在类前面的。对于这两个东西很好区分,可以理解为类成员的访问修饰符是对内的,也就是对它的直接派生类的,而类层次的访问修饰符是对外的,即对类的使用者以及除了直接派生类之外的其他派生类。不管类层次的访问修饰符如何都不影响直接加在类成员上的访问修饰符对派生类的影响。

访问修饰符有三个,作用在成员变量上的时候:

  • private:直接派生类的仍然不能访问的成员类型,同时外部也不能访问。
  • protected:直接派生类能够访问,但是外部不能访问。
  • public:直接派生类和外部都能访问。

访问修饰符有三个,作用来类层次的时候:

  • private:等于整个类对外部都private了,后续的派生类和外部看不到这个类内的任何东西。
  • protected:整个类都被protected了,后续的派生类能够看到protected和public,外部什么都看不见。
  • public:对后续派生类和外部的访问权限等同于没有影响,也就是仍然取决于成员上的访问修饰符。

改变继承成员的访问修饰符

通过 using 能够改变继承成员的访问修饰符,只要原先在子类中的访问修饰符是 privateprotected,就能通过 using 进行访问状态的改变,将访问状态改变相对应的访问状态,具体的访问状态取决于放在 privateprotectedpublic 其中的哪个位置。注意顶多只能恢复原来能看得见的,像 private 这种原来本身就看不见的,是没办法提升访问状态的。

cpp
class A{
    protected:
        void func();
};

class B: private A{
    public:
        using A::func;  
};

int main(){
    B b{};
    b.func();
}

构造函数和析构函数

子类在使用构造函数的时候在初始化列表中使用父类的构造函数就行了。不能在派生类的构造函数的初始化列表中使用基类的成员变量,即使这些成员变量对派生类是可见的也不行。

如果基类中没有非私有的默认构造函数,或者其默认构造函数被删除,那么派生类的默认构造函数也会被删除。(毕竟派生类的默认构造要调基类的默认构造,但是基类的默认构造有找不到。)

在派生类中,也可以使用 using 把基类的构造函数拿出来变成自己的构造函数然后往下传播。与之前使用 using 改变访问修饰符不同,在继承构造函数的时候,使用的 using 放在任何位置都一样。

构造函数的执行顺序是从基类到派生类,基类先进行构造,而后到派生类。析构函数的执行顺序是从派生类到基类逐步析构。

多重继承

多重继承和单继承是一模一样的,就是可能会在继承的时候产生名称的冲突。因此多继承只要解决名称冲突就好了,解决名称冲突的方法有三个,一个是进行强制转换(基本只能向 public 继承的基类进行强制转换),另一个是使用 :: 指定具体的名称(使用的时候仍然要考虑访问修饰符),还有就是使用using。

虛继承

虛继承本质还是多重继承,只是为了解决多重继承中的钻石形继承问题,使用虛继承之后,多个派生类虛继承同一个基类,在创建对象的时候在最深的派生类调用虚继承基类的构造函数,多个钻石形继承共享的仍然是单个对象。