继承
继承机制面向对象程序设计使代码可以复用的最重要手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称为派生类。
继承呈现了面向对象程序设计的层次结构
体现了由简单到复杂的认知过程,继承的类设计层次的复用
1.基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,在语法上限制派生类对象不管在类里面还是类外面都不能去访问它
2.基类private成员在派生类中是不能被访问,基类的私有成员在子类都是不可见的。如果基类的成员需要在子类被访问但不想在类外访问,就定义protected,可以看出保护成员限定符是因继承才出现的
派生类对象可以赋值给基类的对象/基类的指针/基类的引用
在继承体系中基类和派生类都有独立的作用域
子类和父类中有同名成员,子类成员将屏蔽父类同名成员的直接访问,这种情况叫隐藏
也叫重定义(如果需要访问需要指明类域显示访问)
ps:只需要函数名相同就可以构成隐藏
关于子类的默认成员函数
在VS2013环境下(其他编译器大概也是)
通过内存及部分实验观察得知
1.先调用父类的构造函数再调用子类的构造函数
2.父类位于低地址,子类位于高地址
3.析构时,会先析构子类再析构父类(这符合栈的顺序,父类是先入栈的)
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员
基类定义了static静态成员,则整个继承体系里面只有一个这样的成员,无论派生出多少个子类,都只有一个static成员实例
由于C++支持多继承
则会引发菱形继承的问题,即二义性和代码冗余
解决方式:通过虚继承
如果有两个类A,B继承了公共的祖先,然后C同时继承了A,B
通过虚继承,祖先只创建一份,放到虚基表中,A,B中存放着这张表的地址
这张表中存有相对于公共祖先位置的偏移量,通过该偏移量可找到唯一的祖先
继承和组合的关系
组合:在类中直接定义类
耦合度低。
继承 is-a
组合has-a
根据不同的实际场景使用即可
多态
静态的多态:函数重载,看上去相同的函数能处理不同的事情(编译时实现)
动态的多态:不同对象做同一件事情有不同的结果(运行时实现)
条件
必须通过基类的指针或引用被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写
重写三个条件:函数名,参数,返回值必须相同
特殊情况:
1.协变:基类与派生类函数返回值类型允许不同
2.父类+virtual,子类只需满足三同条件即可,即可以不加virtual
原本目的:考虑析构函数的重写(如需要通过父类去释放子类时)
相关关键字
final:
修饰函数,表示该虚函数不能再被重写override:
检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错
抽象类
在虚函数的后见面写上=0,则这个函数为纯虚函数,包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象,派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象,纯虚函数规范了派生类必须重写,另外出喜怒函数更体现处了接口继承
多态的原理:
虚函数表
如果该类中的非静态成员有虚函数,则编译器会为其形成一张虚函数表,并把其地址放在该实例化后的头部(可能不一定,vs2013是这样的)
该类所有对象共用一张该虚函数表(说明该虚函数表存放在常量区)
当继承同一祖先的不同类(假设都有虚函数完成重写),当我们调用该函数时,实际上是去虚表中找对应的重写函数(这就是为什么会传父类的指针或引用,我们只需要找到虚表中对应的重写函数,并不关心这个类是哪一个,即在运行中实现多态)
多继承中的虚函数表
存在多份虚表
多继承派生类的未重写的虚函数在一个继承基类部分的虚函数表中
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)