大家好
欢迎回来继续学习
C++语言程序设计
这一节我们来学习
C++11标准提供的
override和final的新功能
我们知道多态行为的基础
是什么呢
是基类声明一个虚函数
然后呢
派生类要去覆盖这个虚函数的话
就要声明一个
原型完全一样的函数
但是有的时候呢
我们写程序可能会有疏漏
本意可能想写一个虚函数
去覆盖基类的虚函数
但是写的时候呢
可能参数表
或者是返回值
或者什么地方没有把它
定义的跟基类虚函数的原型
完全一致
这个时候
编译器并不会报错
因为编译器
并不知道我们的意图是说
这个函数
是一个覆盖基类虚函数的函数
编译器没办法知道我们这个意图
那所以呢
有的时候我们在派生类中
这个函数原型没有写对的话
就没有达到相应的目的
就实现不了多态了
而这个错误呢
却在运行中反映出来
还比较难调试和定位
这是一个因为疏忽造成了错误
于是没有能够实现多态性的例子
我们看在Base类里面
定义了一个虚函数f1
它是一个const
是一个常成员函数
那么在Derived类里面
我们本来是希望覆盖
这个虚函数f1的
所以定义了一个
同名的参数表也一样
返回值也一样的函数
在这里我们希望覆盖
基类继承过来的虚函数
那这个地方呢
它没有写这个vitual这个关键字
当然就是认为
这个语法规定
只要继承过来这个函数了
那派生类中的同原型的函数
自动都是虚函数了
不用写这个vitual关键字了
确实它是可以缺省的
但是就是疏忽了一点
const也是区别不同
重载函数的一个因素
所以这个有const
和没有const这两个函数原型
它是不同的
所以没有达到
写一个新的虚函数去覆盖
原有继承的虚函数的这样的效果
所以在主函数中
我们用基类的指针
去指向基类的对象
去指向派生类的对象
然后调用f1
结果呢
调用的都是基类的这个f1
没有实现我们希望的多态性
那么这样的错误
是很难查找的
在运行时发现结果
跟我们预期的不一样
但是要找到原因
还是有点麻烦的
那么怎么避免这种情况呢
后面要给大家介绍
C++11引入了一种
显示的函数覆盖的功能
这样的话
编译器在编译期间就会发现
你的本意是想覆盖基类的虚函数
但是你没有写对啊
它就能把这种错误发现
给我们指出来
那么这里呢
就要用到这个override
我们用override说明的函数
就必须在基类中找到
同样原型的这个虚函数
如果你在派生类中
写了一个函数
用override说明了
但是编译器在它的基类中
找不到
跟它相同原型的一个虚函数
编译器就会报错
说这个错了
你没有找到相同原型的这个函数
你就会发现
我想写一个函数去覆盖
结果没写对
那么这样我们就能把错误
在编译阶段就修改了
那这样就避免了运行时
那种不稳定性
运行时发生的错误
其实是挺难调试的
我们定义类的时候
是不是有的时候觉得这个类
它的功能都很关键
我定义了这样一个类
其他人就用就好了
我不希望它被继承和发展
实际上就是不希望它被扩展
这个继承呢
跟我们人类说的那个继承遗产呢
还是有差别的
只要是好东西
我们不会说不希望继承的
但是程序中的继承呢
意味着你一定要对它进行修改的
为什么呢
因为不需要修改
你可以直接使用
拿来用就行了
不用经过一个继承的环节
所以程序中的继承
和我们日常所理解的继承呢
还是些许差别的
所以有的时候呢
我们定义一个类
不希望它被继承
也就是不希望通过这个类
去派生出新类来
想用你就用
但是你不许改它
为什么呢
有时候有的类里面的功能
非常关键
你希望在整个系统中
就这样使用这样统一的功能
不希望它被
功能被覆盖 被修改
不希望接口被屏蔽 对吧
还有的时候呢
并不是一个类里面的所有功能
都如此的关键
可能就是个别的成员函数
它的算法你希望固定
希望在整个系统里面
都用严格的用这同样的算法
而不要去修改
这个时候呢
你可以说这个类可以被继承
但是这个函数不希望被修改
那么这个时候呢
你可以在函数上使用final
去说明
那这个函数就不能被覆盖了
那么现在
我们通过一个具体的例子
来演示一下这个final
我们看在定义Base1的时候呢
加了一个final来修饰
那就说明
定义Base1的人
指明了Base1
是不能派生出新类的
不能当做基类去继承的
那接下来呢
如果在程序的其他部分
我们尝试硬是要从Base1类
派生出Derived类
那么编译器就会报错
因为Base1是final
是不允许被继承的
再看下面这个例子
在Base2里面呢
我们声明这个函数f的时候
这个虚函数f
把它声明为final了
那就说明这个函数
是不能被覆盖的
那接下来
看我们虽然可以从Base2
派生出Derived2
但是
在Derived2这个类中如果尝试
重新定义一个函数f
去覆盖那个继承而来的虚函数
编译器也会报错
因为Base2里面的函数f
是final 是不允许被覆盖的
这个override和final
虽然是C++11提供的新功能
但是它并不是语言的关键字
也就是说
它只在特定的地方
具有特定的含义
在其他地方
如果你用override和final
做一般的标志符使用呢
也仍然是可以的
但是建议大家不要这样用
你就当它是关键字
不要在别的地方
拿它当标志符用
这样免得你的程序可读性
受到影响