1、继承是面向对象复用的手段
三种成员访问限定符 public(公有) protected(保护) private(私有)
三中继承关系 public(公有继承) protected(保护继承) private(私有继承)
继承方式和访问限定符的关系
a、保护成员限定符是因继承才出现的,在基类中保护成员限定符修饰的成员在派生类中依旧可见,两者都是在类中可以访问,在类外面不能被访问
基类的私有成员在派生类中是不可见的,即就算在类中也不可被访问
b、public继承保持is-a原则 每个子类对象就是一个父类对象
protected/protected继承保持has-a原则 基类对象并未完全成为子类接口的一部分
大多数场景下使用的都是public继承
c、在c++中 struct和class都是类的关键字 struct默认继承方式为公有继承 class默认继承方式为私有继承
d、不管使用哪种继承方式,派生类内部都可访问在基类中的public或者protected成员,不同的继承方式继承后的权限会保持不变或者缩小
在基类中的private成员在派生类中都是不可见的
继承与转换
a、public继承(is-a原则),子类对象可以赋值给父类对象(切片/切割) 父类对象不能赋值给子类对象(强转也不可以,只有指针和引用才支持强转)
b、父类的指针/引用可以指向子类对象 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成,但依然有越界的危险)
2、隐藏
同一类中,函数名相同,参数的个数或者类型不同,返回值可同可不同则钩秤重载
子类继承父类,同名函数(名字相同就认为是同名函数,不管参数)发生的是重定义
当子类、父类定义同名成员时,将子类中从父类中继承的成员隐藏/重定义
即父类、子类中出现同名,优先访问子类中的,要想访问父类中的要加域作用访问符,指定访问父类中的成员
3、派生类的默认成员函数
继承后在派生类中如果没有显式的写六个成员函数,那么系统会默认合成六个成员函数
派生类的构造函数要显式的调用父类的构造函数,然后写自己的构造
派生类的拷贝构造也是先显式的调用父类拷贝构造(子类对象给父类是可以的)
派生类的赋值运算符也要显式调用父类赋值运算符重载 而且该函数要加父类的域作用访问符,如果不加会将父类给隐藏了,又有重定义的问题
派生类的析构函数很特殊,析构函数不用显式的调用
a、编译器在编译时会将所有析构函数名转为~destory(),所以显式的写子类会把父类给隐藏了
b、如果显式调用父类的析构函数并且在其前面加上父类的域作用访问符,比如有三个对象,但析构父类会调六次
因为构造函数在构造的时候先定义父再定义子(因为栈是先进后出的),所以析构的时候会先析构子再析构父
c、所以析构的合成不允许显式的调父类的析构(因为不符合栈先进后出) 编译器不放权给我们显式的调,它会在调完子后自动调父
4、单继承 一个子类只有一个直接父类
多继承 一个子类有两个及以上的父类
怎么解决菱形继承存在二义性和数据冗余的问题?
a、非虚继承 用域访问限定符解决二义性的情况
b、虚继承 解决了菱形继承中子类对象包含多份父类对象的数据冗余和浪费空间的问题
(虚继承的缺点:复杂 影响效率)(怎么避免:不要设计多继承)