深刻理解 C++多态

定义

多态的定义简单来说就是使一条语句有多种状态。

实现方式
多态的实现方式分为三块:重载、重写、重定义。下面我们来谈一谈他们各自的实现方式和实现原理。

重载

实现方式
重载是在同一作用域内(不管是模块内还是类内,只要是在同一作用域内),具有相同函数名,不同的形参个数或者形参类型。返回值可以相同也可以不同(在函数名、形参个数、形参类型都相同而返回值类型不同的情况下无法构成重载,编译器报错。这个道理很简单,在函数调用的时候是不看返回值类型的)。

实现原理
重载是一种静态多态,即在编译的时候确定的。C++实现重载的方式是跟编译器有关,编译过后C++的函数名会发生改变,会带有形参个数、类型以及返回值类型的信息(虽然带有返回值类型但是返回值类型不能区分这个函数),所以编译器能够区分具有不同形参个数或者类型以及相同函数名的函数。插一句,在C语言中编译器编译过后函数名中不会带有形参个数以及类型的信息,因此C语言没有重载的特性。由此带来麻烦的一点是如果想要在C++中调用C语言的库,需要特殊的操作(extern “C”{})。库中的函数经过C编译器编译的话会生成不带有形参信息的函数名,而用C++的编译器编译过后会生成带有形参信息的函数名,因此将会找不到这个函数。extern “C”{}的作用是使在这个作用域中的语句用C编译器编译,这样就不会出错。这也是一种语言兼容性的问题。

重写

实现方式
重写是在不同作用域内(一个在父类一个在子类),函数名、形参个数、形参类型、返回值类型都相同并且父类中带有virtual关键字(换言之子类中带不带virtual都没有关系)。有一种特殊的情况:函数返回值类型可以不同但是必须是指针或者引用,并且两个虚函数的返回值之间必须要构成父子类关系。这种情况称之为协变,也是一种重写。引入协变的好处是为了避免危险的类型转换。

实现原理
重写是一种动态多态,即在运行时确定的。C++实现重写的方式也跟编译器有关,编译器在实例化一个具有虚函数的类时会生成一个vptr指针(这就是为什么静态函数、友元函数不能声明为虚函数,因为它们不实例化也可以调用,而虚函数必须要实例化,这也是为什么构造函数不能声明为虚函数,因为你要调用虚函数必须得要有vptr指针,而构造函数此时还没有被调用,内存中还不存在vptr指针,逻辑上矛盾了)。vptr指针在类的内存空间中占最低地址的四字节。vptr指针指向的空间称为虚函数表,vptr指针指向其表头,在虚函数表里面按声明顺序存放了虚函数的函数指针,如果在子类中重写了,在子类的内存空间中也会产生一个vptr指针,同时会把父类的虚函数表copy一下当做自己的,然后如果在子类中重新声明了虚函数,会按声明顺序接在父类的虚函数函数指针下。而子类中重写的虚函数则会替换掉虚函数表中原先父类的虚函数函数指针。重点来了,在调用虚函数时,不管调用他的是父类的指针、引用还是子类的指针、引用,他都不管,只看他所指向或者引用的对象的类型(这也称为动态联编),如果是父类的对象,那就调用父类里面的vptr指针然后找到相应的虚函数,如果是子类的对象,那就调用子类里面的vptr指针然后找到相应的虚函数。当然这样子的过程相比静态多态而言,时间和空间上的开销都多了(这也是为什么内联函数为什么不能声明为虚函数,因为这和内联函数加快执行速度的初衷相矛盾)。

重定义

实现方式
重定义是在不同作用域内的(一个在父类一个在子类),只要函数名相同,且不构成重写,均称之为重定义

实现原理
重定义的实现原理跟继承树中函数的寻找方式有关,他会从当前对象的类作用域内开始查找同名的函数,如果没有找到就一直向上查找直到基类为止。如果找到一个同名的函数就停止。这也就说明他不管函数的形参类型或者个数是不是一样,只要函数名一样,他就认为是找到了,如果这时候形参类型或者个数不一致,编译器就会报错。多重继承的查找,如果在同一层内出现一样的函数声明那么编译器会报错不知道调用哪一个函数,这类问题也叫钻石继承问题。钻石问题的解决方案可以通过虚继承来实现,这样就不会存在多个一样的函数声明。

最后

  •    多态是通过虚函数来实现的,虚函数的使用本质就是将派生类类型的指针赋给基类类型的指针,虚函数被调用时会动态的判断调用对象的类型,从而给出相应的响应
  •    虚函数是成员函数,而且是非静态的成员函数,如果某类中的一个成员函数被说明为虚函数,这就意味着该成员函数在派生类中可能有不同的实现
  •    在定义一个表达抽象概念的基类时,有时可能会无法给出某些成员函数的具体实现,这时,就可以将这些函数声明为纯虚函数

1、重载

        在同一个作用域,具有相同的函数名,只是参数的类型、个数不同(必须条件),返回值类型不同;

2、重写

        不同作用域内,父类中带有virtual关键字,子类中定义实现,或者父类中定义为纯虚函数;

3、重定义

        在不同的作用域内,函数名相同且不构成重写的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑化草莓熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值