普通人买全价,学生半价
多肽
构成条件
1.虚函数重写
2.父类的指针或者引用去调用虚函数
两个virtual没有关联
函数前面增加virtual虚函数,p是父类的引用,既可以传父类对象也可以传子类对象
去掉引用(子类传给父类,切片了) 不是多肽了
虚函数重写 (重载)
条件:
父子继承关系中的两个虚函数,三同 (函数名、参数,返回值)
virtual只能修饰成员函数
大坑->协变
三同 (函数名、参数,返回值)返回值有一个例外
协变->必须是父子类关系的 指针或者引用
幺蛾子
父类不可以不加virtual,子类(派生类)必须加virtual(可以理解成重写父类的实现)
总结:派生类可以不加virtual(建议加上,不加也不错 )
派生类析构必须先子后父(自动)先父后子会出错
这里父类对象调用父类析构,但是子类对象也调用了父类析构(因为p有可能指向父类也可能是子类)因为子类的析构函数跟父类的析构函数形成隐藏关系
子类父类析构不是同名为什么构成隐藏?因为多 肽原因析构会被统一处理成 destructor,
这里delete p 调用的是p->destrutor()+operator delete(p),这里delete先调用destructor再调用operator delete(p),调用destructor时候是普通调用,普通调用调用看p类型,但是我们不希望是普通土调用,希望是多肽调用(指向父类调父类,指向子类调子类)
此时如果构成多肽,他的条件有
1.父类的指针或者引用去调用虚函数(满足了)
2.虚函数重写
父子继承关系中的:
1.两个虚函数
2.三同 (函数名、参数,返回值)参数的类型
这里返回值,参数都没有,只有函数名不同但是进行了特殊处理.
改成虚函数,次数就构成多肽了(就能正常析构了)
也就是说当析构函数是虚函数时,才能正确调用析构函数(否则可能内存泄漏)
为了防止子类virtual忘记写所以祖师爷就设置特例可以子类不写virtual就完成重写
多肽调用
普通调用:调用函数的类型是谁,就是谁的调用函数(这个类型的函数)
多肽调用:调用的指针或者引用指向的对象,指向父类调用父类的函数,指向子类调用子类的函数
破坏多肽的调用条件
1.破坏继承关系(不继承了),不继承压根不能传参了
2.如果不是指针也不是引用吗,就是普通调用了,调用函数的类型是谁,就是谁的调用函数(这个类型的函数)
重写可以理解为继承了父类比如继承了一个函数并且 重写了这个函数
第一个ptr是父类的指针(或引用)调用的不是重写的虚函数
这样的危害就是,如果student没有什么资源还好,如有的话就没有进行清理,会造成内存泄漏
给析构函数加virtual后构成多肽(析构名称不同默认做特殊处理(相同)构成虚函数重写)
干脆派生类的析构也不用写了
总结:派生类(子类)函数和析构都不用加virtual了
继承下来是可以用,三同中参数看的是参数的类型
下面这道题
继承的是父类的接口,重写的是他的实现(用的是父类的接口1 )
这里没有构成多肽,因为p不是父类的指针或者引用调用的
重载,覆盖(重写),隐藏(重定义)的对比
finial修饰 类,这个类不能被继承
修饰 虚函数,这个虚函数就不能被重写
override
修饰子类的虚函数,检查是否完成重写,如果没有完成重写就报错
抽象类
虚函数后面加 =0
纯虚函数:抽象类不能实例化对象(不存在父类对象/没有父类对象),(指针可以 Car*c)
抽象类他的子类也不能实例化对象(继承了父类),除非把这个纯虚函数进行重写,
多肽的另一种形态,父类是纯虚函数不存在父类对象
但是他有多个子类,多肽就运用到子类上,一定程度上说纯虚函数,强制(间接)子类去重写父类的纯虚函数
抽象类,可以理解为不具有实体,不需要实例化
接口继承和实现继承
c++会把虚函数地址存到 虚函数表里面去,只要是虚函数就要多考虑一个指针
虚函数编译以后在内存会存到 代码段(指令都到代码段)
他是一个指针数组,里面存的指针,存的函数指针,虚函数指针数组
多肽原理
父类对象P
子类对象s,他的虚表指针跟父类不是一个指针
虚函数的重写也叫(覆盖)他把父类的虚表拷贝过来,重写这两个被继承的虚函数,子类虚表被覆盖,覆盖成新的虚函数
第二行fun地址没有变,说明只重写了虚函数buyticket(覆盖)
多肽的原理是什么?,下面的vfptr是从子类中切割出来的父类然后访问BuyTicket
1.构成多肽,p是一个父类对象传给父类指针,就是说父类指针ptr指向父类对象p,从父类对象中找到虚函数表的地址,再拿到dc154300,ptr指向子类,从子类中切片出父类,从父类中找到虚函数表的地址也callc8154500(虚表不一样),所以就说明白了指向父类调父类。指向子类调子类
引用同理
对象不行,对象不能形成多肽 ,对象要拷贝过来,他不会拷贝把虚表指针拷贝下来,切割出子类对象中父类那一部分,成员会拷贝给父类对象ptr,但是不会把父类的虚函数指针拷贝下来
如果假设父类对象=(赋值)子类对象会拷贝虚函数表指针
父类对象不能保证一定是父类虚表
这样的话一个引用或者指针指向父类ptr就不能保证,指向父类调父类,指向子类调子类
这里*p=s,析构函数可能调错!子类对象赋值给父类p,因为析构函数也在虚表里面重写了,这时候p被覆盖成子类的虚表,析构时候调用子类的析构函数,这里竟然成了父类对象调用子类的虚函数! ,
所以多肽的形成是父类的指针或引用(不能子类,因为父类不能给子类)也不能是对象直接拷贝,拷贝会形成问题
如果子类不重写虚函数,父类和子类对象的虚表是否一样?
重写了肯定不一样,不重写也不一样(虽然可以一样但是编译器不允许,省去麻烦)
同类函数(对象p1,p2,p3,他们都是父类对象啊)虚表一样么?
一样(公用虚表)不同的类就不同