c++21,22多肽

本文详细阐述了C++中虚函数的使用、多肽概念、派生类的继承与重写,包括析构函数的特殊性,以及虚函数表的作用。重点讨论了多肽调用的条件、隐藏关系和重写机制,强调了虚函数的重要性以避免内存泄漏。
摘要由CSDN通过智能技术生成

普通人买全价,学生半价 

多肽

构成条件

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,他们都是父类对象啊)虚表一样么?

一样(公用虚表)不同的类就不同

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值