C++第三特性——多态

        生活中我们不但有父与子的继承关系,还有 面对一种事物 不同行为的多态关系。比如对于售票而言,普通人去则是排队全价买票,但是对于学生而言,则会有半价优惠,对于军人而言则会有军人优先通道 。

构成多态的条件:

 虚函数的重写:

        提到多态就不得不提及虚函数,这时我们又得引入一个熟悉的关键字——“virtual”。没错,这与我们在学习继承时解决菱形继承产生二义性问题时所用的“虚继承”关键字一样。不过 这里我们用它来标识虚函数。

虚函数重写的三大条件:(缺一不可)

派生类中有一个跟基类完全相同的虚函数 ( 即派生类虚函数与基类虚函数的
1.返回值类型完全相同
2.函数名字完全相同
3.参数列表完全相同

 上面我们可以看到,父类 调用了父类的虚函数,子类调用了子类的虚函数。

重写的特例——协变、析构函数的重写

协变:派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指

针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。
 

 Student类并未加关键字,但是依旧构成虚函数重写。值得注意的是

 若把虚函数的返回值父类和子类交换则不构成协变。

析构函数的重写:

如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字, 都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同, 看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处 理,编译后析构函数的名称统一处理成destructor

 如图所示,我们在使用父类指向子类new出的空间时,若未完成析构函数的重写,则会调用父类析构,而父类析构显然不能删除new出的子类空间,则会报错。所以建议父类的析构函数写成虚函数类型。

重写,重载,重定义——

关于虚表

        这里我们对比a,b发现,b除了成员变量_b外,还存储了一个函数指针,对象中的这个指针我们叫做虚函数表指针。 对比A,B,C大小时候我们发现,虽然C中虽然为空类,但他依旧可以被实例化,所以我们所给大小为1,而A,B,我们可以看到B中显然多了一个函数指针,所以比A大4个字节(32位系统下)。

        虚表存的是虚函数指针,不是虚函数,虚函数和普通函数一样的,都是存在代码段的,只是 他的指针又存到了虚表中。另外对象中存的不是虚表,存的是虚表指针。

1.基类中有虚函数,如果子类中没有重写基类的虚函数,此时子类与基类共用同一张虚表

 若完成重写,则子类和父类共享该虚表


这里我们可以看到,func1完成了重写,所以被放进虚表中且对象 d 虚表中func1为重写的函数,可理解为将原虚表func1覆盖。而func2未完成重写,但是加了virtual关键字,因此也被放入虚表,不过与父类为同一函数。func3没有virtual关键字,所以只是单纯继承下来。 

抽象类与纯虚函数

        在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口 类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值