继承
继承的语法
class 子类 : 继承方式(public/private/protected) 父类{};
继承方式
private,public,protected的访问范围:
- private: 只能由该类中的函数、其友元函数访问,不能被任何其他访问,该类的对象也不能访问.
- protected: 可以被该类中的函数、子类的函数、以及其友元函数访问,但不能被该类的对象访问
- public: 可被任意访问
特殊情况:使用private继承时的一种特殊机制(准许访问)
某些情况下,需要在子类中以private方式继承的成员恢复其在基类中的public或protected的访问权限。
- 方法一: 使用using 语句;
- 方法二: 使用访问声明,形式为 base-class::member;, 位置在子类中适当的访问声明处。(注,只能恢复原有访问权限,而不能提高或降低)
继承的一些性质
继承中的对象模型
子类继承父类所有属性,就连private的也继承,只是会被编译器隐藏,不可访问,所以sizeof(子类)的时候不要忘记加上父类中private的属性。
构造和析构顺序
父类构造-子类构造-子类析构-父类析构。
跟class B调用class A中的对象一样,也是先A构造-B构造-B析构-A析构。
同名成员处理
如果子类和父类有相同名称的成员age,则子类的对象直接调用s.age会调用到子类的对象的age。如果想要调用父类的age,则要写成s.父类::age。
同名静态成员处理
静态成员有两种调用方法,除了通过创建对象调用,还可以直接用类::静态成员调用。
创建对象调用
静态成员age
如果子类和父类有相同名称的静态成员age,比如static int age(类内声明,类外初始化int age=10;),那么同样的,子类的对象直接调用s.age会调用到子类的age。如果想要调用父类的age,则要写成s.父类::age。
成员函数func()
如果子类和父类有相同名称的静态成员函数func(),比如static int func(){},那么同样的,子类的对象直接调用s.func()会调用到子类的func()如果想要调用父类的age,则要写成s.父类::func()。
注意,子类也会屏蔽父类函数所有的重载,所以哪怕调用的是s.func(int),子类没有func()的有参函数而父类有,编译器也会默认调用子类,所以这种情况下会报错。
类::静态成员调用
静态成员age
子类::静态成员age会调用到子类的age。如果想要调用父类的age,则要写成子类::父类::age。
成员函数func()
子类::func()会调用到子类的func。如果想要调用父类的age,则要写成子类::父类::func()。
注意,子类也会屏蔽父类函数所有的重载,所以哪怕调用的是s.func(int),子类没有func()的有参函数而父类有,编译器也会默认调用子类,所以这种情况下会报错。
继承对象语法
比如class D想同时继承A、B、C,可以:
class D:public A, public B, protected C{};
菱形继承问题以及解决方法:
A被B、C继承,B、C又同时被D继承,那么存在两个问题。
A、B有同名成员,D如何调用
D.A::age和D.B::age
D只想保留一份数据,D如何操作
虚继承,也即:
class B:virtual public A{};
class C:virtual public A{};