修改重写方法的特征

在大多数情况下,我们重写(override)一个 virtual 方法是为了改变它的实现。然后,有时我们却想改变该 virtual 方法的其他的特征,这往往会带来一系列问题。

1)改变方法的返回值类型

通常,子类在重写方法时,要保持与父类一致的函数原型,方法的实现可以改变,但是原型需要保持不变。

然而,事实却并非如此。在C++中,如果父类的 virtual 方法的返回值类型是某个类(假定为类A)的指针或者引用,那么在子类中 override 该方法时,可以将其返回值改变为子类(类A的子类)的指针或者引用。这就是所谓的协变返回类型(covariant return types)。当父类与子类工作在 parallel hierarchy 中时,这个 feature 将会派上用场。注意,parallel hierarchy 是指,一个层次结构与另一个层次结构没有相交,但是存在联系。

我们来考虑一个樱桃果园模拟程序,如下图所示,就是一个parallel hierarchy ,

现在假定 Cherry Tree 类有一个 pick() 方法,这个方法的功能是从树上摘下一个樱桃:

很自然,在 BingCherryTree 子类中,我们会想 override 该 pick() 方法。由于 BingCherry 是一个 Cherry,在下面的代码中,我们可以使方法的原型保持不变。BingCherry指针将自动转换为 Cherry 指针(向上转型)。

以上的实现很好,但是,能不能更进一步呢?因为我们知道,BingCherryTree 返回的实际上是一个更为具体的BingCherry,因此,我们可以通过修改返回值类型(将 Cherry * 修改为 BingCherry *)向BingCherryTree 类的用户指明这一点,如下所示:

这里一个好的方法来判断是否可以在重写方法时改变其返回值类型:我们可以考虑在修改返回值类型后,原来已有的代码是否仍然可以良好运行。在之前的示例中,修改返回值类型没有问题,因为假定 BingCherryTree 类的 pick() 方法总是返回 Cherry * 的代码仍然可以成功编译并正常运行。道理很简单,BingCherry 是一个 Cherry,在返回 Cherry * 的地方返回 BingCherry * 总是没有问题的。

需要注意的是,我们不能在重写方法时,将返回值类型修改为完全不想关的类型,例如 void *。

小结:对于父类中的某个 virtual 方法,只要子类中某个方法与该 virtual 方法的名字以及参数列表完全相同,那么编译器即认为子类将 override 该方法,此时如果返回值类型兼容,那么没有问题,如果不兼容,编译器将会报错。

2) 修改方法的参数

如果在子类的定义中使用父类 virtual 方法的名称,但参数与父类中同名方法的参数不同,那么这不是在 override 父类的方法,而是在创建一个新方法。而父类原始的同名方法将被隐藏。

当然,我们可以使用一种较为晦涩的技术兼顾被隐藏的方法,那就是使用 using 关键字。

小结:对于非虚方法,只要重名即为隐藏。对于 virtual 方法,名字以及参数完全一样则认为子类试图 override 父类方法,如果返回值类型兼容则 override 成功,返回值类型不兼容,则报错。

3) The override keyword(C++11)

有的时候,我们本意是想 override 父类的一个 virtual 方法,但是可能一不小心,就变成隐藏父类的 virtual 方法了。来看以下例子:

我们可以通过引用来调用 Method() 方法,如下所示:

代码将正确地调用 Sub 类重写的 Method()。现在假定 override Method() 时,我们使用了int(而非double,如此一来,改变了参数类型,不再时override),如下所示:

显然,以上代码并没有 override Method() 方法,而是创建了一个新的 virtual 方法(隐藏了父类的 Method() 方法)。如果我们仍然试图像刚刚一样去调用 Method(),将会调用的是 Super 的 Method(),而非 Sub 类中定义的那个方法(多态)。

如果我们在实际的工程中,由于需求变更而修改了父类的某个 virtual 方法的函数原型,而此时却没有相应改变子类的实现。那么实际在子类中就是创建了一个新的 virtual 方法(同时,隐藏了父类的 virtual 方法),而不是 override 了父类的 virtual 方法。

此时,根据 C++11 标准,我们可以采用 override 关键字来避免这种情况,如下所示:

Sub 的定义将导致编译器报错,因为 override 关键字表明我们要重写 Super 类的 Method() 方法,但在 Super 类中的 Method() 方法参数为 double,因此在子类中并没有实现 override。

Changing the Overridden Method’s Characteristics的更多相关文章

  1. What Influences Method Call Performance in Java?--reference

    reference from:https://www.voxxed.com/blog/2015/02/too-fast-too-megamorphic-what-influences-method-c ...

  2. Override is not allowed when implementing interface method Bytecode Version Overriding and Hiding Methods

    java - @Override is not allowed when implementing interface method - Stack Overflow https://stackove ...

  3. CLR via C# 3rd - 08 - Methods

       Kinds of methods        Constructors      Type constructors      Overload operators      Type con ...

  4. Java Interview Reference Guide--reference

    Part 1 http://techmytalk.com/2014/01/24/java-interview-reference-guide-part-1/ Posted on January 24, ...

  5. Java Knowledge series 7

    Pepole who make a greate contribution on common libaraies deserve our respect. Component(Widget) / S ...

  6. Using default security password

    不展示Using default security password的解决办法: import org.springframework.context.annotation.Bean; import ...

  7. 关于C#你应该知道的2000件事

    原文 关于C#你应该知道的2000件事 下面列出了迄今为止你应该了解的关于C#博客的2000件事的所有帖子. 帖子总数= 1,219 大会 #11 -检查IL使用程序Ildasm.exe d #179 ...

  8. spring mvc DispatcherServlet详解之前传---FrameworkServlet

    做项目时碰到Controller不能使用aop进行拦截,从网上搜索得知:使用spring mvc 启动了两个context:applicationContext 和WebapplicationCont ...

  9. Java基础知识【上】(转载)

    http://blog.csdn.net/silentbalanceyh/article/details/4608272 (最终还是决定重新写一份Java基础相关的内容,原来因为在写这一个章节的时候没 ...

随机推荐

  1. 用js进行日期的加减

    如题,开始查了查js的使用文档,但没发现可以直接用的函数,于是就想自己写函数来着,这就要涉及到每个月天数的判断,如果是2月份的话,还要涉及到闰年的判断,虽然不复杂但我想js应该不会这么低级,于是查了下 ...

  2. sychronized面试问题浅析

    先说下面试吧,整体来说基础准备好点,简历别太假,然后回答起来实事求是,表现自然的点基本上都没问题吧(针对初级职位,记得有个hr说过对于新人基础扎实和为人真诚是最关键的),两天时间跑起来挺累,反而觉得面 ...

  3. 魔兽世界私服Trinity,从源码开始

    缘起因由 在一个无所事事的周末下午,突然想起魔兽世界,官方的账号很久没有上了,里面的大小号现在连满级都不是.以前曾经搭过传奇和星际争霸战网的私服自娱自乐,也听说过魔兽世界有开源的服务端模拟,既然兴致来 ...

  4. web 性能忧化(IIS篇)

    1. 调整IIS 7应用程序池队列长度 由原来的默认1000改为65535. IIS Manager > ApplicationPools > Advanced Settings 2.   ...

  5. 分布式架构--第一篇--项目拆分(maven命令生成多模块项目)

    预览生成的项目结构: ying-yue-parent // 顶级总编译控制模块 ying-yue-lib // jar模块 ying-yue-model // 模型对象模块 ying-yue-dao ...

  6. 20145129 《Java程序设计》第8周学习总结

    20145129 <Java程序设计>第8周学习总结 教材学习内容总结 NIO NIO使用频道(channel)来衔接数据节点,对数据区的标记提供了clear(),rewind(),fli ...

  7. 四则运算小程序测试--c++--软件工程课

    一.测试内容: 1.生成题目数是否准确?2.打印方式(列数l.行间距jj)是否准确?3.有无乘除法cc是否准确?4.数的范围fw是否准确?5.除法有无余数c是否准确?6.加减有无负数f是否准确? 二. ...

  8. ubuntu cron.hourly不运行

    服务器没有装NTP,要每天向特定的server进行时间同步,写了一个定时任务,放在/etc/cron.daily下,但是不运行. /etc/crontab文件: # /etc/crontab: sys ...

  9. Careercup - Microsoft面试题 - 5752271719628800

    2014-05-10 20:31 题目链接 原题: Given an array of integers and a length L, find a sub-array of length L su ...

  10. Tomcat配置HTTPS方式生成安全证书

    在Tomcat 6中配置SSL双向认证是相当容易的,本文将介绍如何使用JDK的keytool来为Tomcat配置双向SSL认证.并实现批量生成证书 系统需求:JDK 5.0Tomcat 6.0.16启 ...