虚函数读书笔记

成员函数与继承
派生类可以继承其基类的成员,然而当遇到与类型相关的操作时,派生类必须对其重新定义。换句话说,派生类需要对这些操作提供自己的新定义以覆盖(override)从基类继承而来的旧定义。
在C++语言中,基类必须将它的两种成员函数分开来:一种是基类希望其派生类进行覆盖的函数;另一种是基类希望派生类直接继承而不要改变的函数。对于前者,基类通常将其定义为虚函数(virtual)。当我们使用指针或引用调用虚函数时,该调用将被动态绑定。根据引用或指针所绑定的对象类型不同,该调用可能执行基类的版本,也可能执行某个派生类的版本。
基类通过在其成员函数的声明语句之前加上virtual使得该函数执行动态绑定。任何构造函数之外的非静态函数都可以是虚函数关键字virtual只能出现在类内部的声明语句之前而不能用于类外部的函数定义如果基类把一个函数声明成虚函数,则该函数在派生类中隐式地也是虚函数
成员函数如果没被声明为虚函数,则其解析过程发生在编译时而非运行时。对虚函数的调用可能在运行时才被解析。当某个虚函数通过指针或引用调用时,编译器产生的代码知道运行时才能确定应该调用哪个版本的函数。被调用的函数是与绑定到指针或引用上的对象的动态类型相匹配的那一个。
必须要搞清楚的一点是,动态绑定只有当我们通过指针或引用调用虚函数时才会发生。当我们通过一个具有普通类型(非引用非指针)的表达式调用虚函数时,在编译时就会将调用的版本确定下来。

关键概念:C++的多态性
OOP的核心思想是多态性(polymorphism)。我们把具有继承关系的多个类型称为多态类型,因为我们使用这些类型的“多种形式”而无须在意它们的差异。引用或指针的静态类型与动态类型不同这一事实正是C++支持多态性的根本所在。
当我们使用基类的引用或指针调用基类中的定义的一个函数时,我们并不知道该函数真正作用的对象是什么类型,因为它可能是一个基类的对象也可能是一个派生类的对象。如果该函数是虚函数,则只到运行时才会决定到底执行哪个版本,判断的依据是引用或指针所绑定的对象的真实类型。
另一方面,对非虚函数的调用在编译时进行绑定。类似的,通过对象进行的函数(虚函数或非虚函数)调用也在编译时绑定。对象的类型是确定不变的,我们无论如何都不可能令对象的动态类型与静态类型不一致。因此,通过对象进行的函数调用将在编译时绑定到该对象所属类中的函数版本上。
当且晋档对通过指针或引用调用虚函数时,才会在运行时解析该调用,也只有在这种情况下对象的动态类型才有可能与静态类型不同。

派生类中的虚函数
派生类经常(不总是)覆盖它的继承的虚函数。如果派生类没有覆盖其基类中的某个虚函数,则该虚函数的行为类似于其他的普通成员,派生类会直接继承其在基类中版本。
派生类可以在他覆盖的函数前使用virtual关键字,但不是非得这么做。派生类如果定义一个函数与基类中虚函数的名字相同但是形参列表不同,这仍然是合法的行为。编译器将认为新定义的这个函数与基类中原有的函数是相互独立的。这时,派生类的函数并没有覆盖掉基类中的版本。就实际的变成习惯而言,这种声明往往意味着发生了错误,因为我们可能原本希望派生类能覆盖基类中的虚函数,但是一不小心把形参列表弄错了。
要想调试并发现这样的错误显然非常困难。在C++11中我们可以使用override关键字来说明派生类中的虚函数。这么做的好处是在使得程序员的意图更加清晰的同时让编译器可以为我们发现一些错误,后者在编程实际中显得更加重要。如果使用override标记某个函数,但该函数并没有覆盖已存在的虚函数,此时编译器将报错。
我们还能把某个函数指定为final,如果我们已经把函数定义成final,则之后任何尝试覆盖该函数的操作都将引发错误。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值