Changing the Overridden Method’s Characteristics
修改重写方法的特征
在大多数情况下,我们重写(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的更多相关文章
- 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 ...
- 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 ...
- CLR via C# 3rd - 08 - Methods
Kinds of methods Constructors Type constructors Overload operators Type con ...
- Java Interview Reference Guide--reference
Part 1 http://techmytalk.com/2014/01/24/java-interview-reference-guide-part-1/ Posted on January 24, ...
- Java Knowledge series 7
Pepole who make a greate contribution on common libaraies deserve our respect. Component(Widget) / S ...
- Using default security password
不展示Using default security password的解决办法: import org.springframework.context.annotation.Bean; import ...
- 关于C#你应该知道的2000件事
原文 关于C#你应该知道的2000件事 下面列出了迄今为止你应该了解的关于C#博客的2000件事的所有帖子. 帖子总数= 1,219 大会 #11 -检查IL使用程序Ildasm.exe d #179 ...
- spring mvc DispatcherServlet详解之前传---FrameworkServlet
做项目时碰到Controller不能使用aop进行拦截,从网上搜索得知:使用spring mvc 启动了两个context:applicationContext 和WebapplicationCont ...
- Java基础知识【上】(转载)
http://blog.csdn.net/silentbalanceyh/article/details/4608272 (最终还是决定重新写一份Java基础相关的内容,原来因为在写这一个章节的时候没 ...
随机推荐
- Oracle连乘聚合函数 MUL
Oracle提供了求和(SUM),平均值(AVG)等聚合函数,但没有提供连乘的聚合函数. 比如有一个表如下: ID NUM 1 4 2 2 3 2 如果要求NUM列的连乘数,即求: 4*2*2 ,目前 ...
- ssh 安装
一 ssh 1.查看ssh服务的状态 输入以下命令: sudo service sshd status 如果出现 Loaded: error (Reason: No such file or dire ...
- iOS学习之Object-C语言简单的通讯录管理系统
用这几天学的OC的知识,写了一个实现简单功能的通讯录管理系统,在这里分享给大家: 通讯录管理系统 * 需求: 1.定义联系人类Contact.实例变量:姓名(拼音,首字母大写).性别.电话号码.住址 ...
- JSON数组操作
在jquery中处理JSON数组的情况中遍历用到的比较多,但是用添加移除这些好像不是太多. 今天试过json[i].remove(),json.remove(i)之后都不行,看网页的DOM对象中好像J ...
- Qt入门1---widget、mainwindow和Dialog区别
摘要: 看了一个月的Qt,居然没有理清Qt中 ------------------------------------ 1.QMainWindow A main window provides a f ...
- 一个关于C#中基类与接口混合继承的疑问总结
思路参照 http://www.cnblogs.com/allenlooplee/archive/2004/11/16/64553.html,对原文进行了简化和补充,感谢原作者. 问题很简单,如下所示 ...
- mysql 存储过程 -- 游标的使用(备忘)
BEGIN ; DECLARE f_ratio FLOAT DEFAULT 0.8; ); ); DECLARE i_statDate DATE; DECLARE i_accumulateCount ...
- 你所必须掌握的三种异步编程方法callbacks,listeners,promise
目录: 前言 Callbacks Listeners Promise 前言 coder都知道,javascript语言运行环境是单线程的,这意味着任何两行代码都不能同时运行.多任务同时进行时,实质上形 ...
- 2. ProGit-Git基础
(1) 取得项目的Git仓库 从工作目录中初始化新仓库 git init 从现有仓库克隆 git clone ssh协议 http协议 (2) 检查当前文件状态 git status (3) ...
- mysql的简单主从复制(ubuntu)
环境:两台ubuntu 12.04.5 虚拟机 mysql-server-5.5 master (192.168.240.130) slave (192.168.240.129) (1)查看二进 ...
