C++11学习笔记(5) —— override and final (转)
原文转自 http://blog.csdn.net/fire_lord/article/details/8540592
1.简介
C++为我们提供了继承和虚函数的重写特性。 在派生类中,重写虚函数不强制要求使用 virtual 关键字,并且C++并没有要求强制检查虚函数的重写是否真正覆盖了基类的虚函数,因为在派生类中,也可以增添新的虚函数,以供下一级的派生类重写。由于检查的不够严谨,就有可能产生错误。
2.有可能产生的错误
最常见的错误就是派生类想要重写基类的虚函数,但是由于参数类型的不同,导致结果和预期不同,例如:

#include"stdafx.h"
#include<iostream> using namespace std; class BaseClass
{
public:
BaseClass(){}
~BaseClass(){}
public:
virtual void func(int param) { cout << "BaseClass::func. param = " << param <<endl; }
virtual void func2() const { cout<< "BaseClass::func2."<<endl;}
}; class DeriveClass : public BaseClass
{
public:
DeriveClass(){}
~DeriveClass(){}
public:
virtual void func(float param) { cout << "DeriveClass::func. param = " << param <<endl; }
virtual void func2() { cout<< "DeriveClass::func2."<<endl;}
}; int main()
{
BaseClass* pBase = new BaseClass();
pBase->func(1);
pBase->func2(); cout<<endl; DeriveClass* pDerive = new DeriveClass();
pDerive->func(4);
pDerive->func2(); cout<<endl; BaseClass* pTest = new DeriveClass();
pTest->func(5);
pTest->func2(); cout<<endl; system("pause");
return 0;
}
输出结果为
对于函数func,派生类和基类的参数类型不同,虽然函数的返回值和函数名相同,并使用了virtual进行虚函数的声明,但实际上派生类并没有重写基类的虚函数,而是定义了自己的虚函数。使用const 进行限定也是一样,在基类中func2 为 const 函数,而派生类没有 const 进行限定,因此,派生类也并没有重写基类的虚函数。 pTest 的输出结果和我们原本预期的并不相同,其调用的是基类的虚函数。由上图输出结果可以看出。
3. override
为了避免上述问题的发生,C++11增添了override, override并不是一个关键字,而是一个用于标记虚函数重写的标识符,使用override 标记的类成员函数表示我们希望其重写基类相对应的虚函数。如果没有重写,编译器会报错。例如:

class BaseClass
{
public:
BaseClass(){}
~BaseClass(){}
public:
virtual void func(int param) { cout << "BaseClass::func. param = " << param <<endl; }
virtual void func2() const { cout<< "BaseClass::func2."<<endl;}
}; class DeriveClass : public BaseClass
{
public:
DeriveClass(){}
~DeriveClass(){}
public:
//error C3668: 'DeriveClass::func' : method with override specifier 'override' did not override any base class methods
virtual void func(float param) override { cout << "DeriveClass::func. param = " << param <<endl; } //error C3668: 'DeriveClass::func2' : method with override specifier 'override' did not override any base class methods
virtual void func2() override { cout<< "DeriveClass::func2."<<endl;}
};
对DeriveClass 的两个成员函数使用了 override ,编译器知道我们期望重写基类的虚函数,但是由于基类并没有相匹配的虚函数,因此编译出错,出错信息如上述注释部分所示。
4.final
在一些情况下,我们并不希望某个成员函数再被任何派生类所继承,在Java语言中,有final来进行限定,C++11也提供了 final (同 override一样不是关键字,只是特殊的标识符)。通过使用final对虚函数的限定,任何子类不能重写该函数,例如:

class BaseClass
{
public:
BaseClass(){}
~BaseClass(){}
public:
virtual void func(int param) final { cout << "BaseClass::func. param = " << param <<endl; }
}; class DeriveClass : public BaseClass
{
public:
DeriveClass(){}
~DeriveClass(){}
public:
//error C3248: 'BaseClass::func': function declared as 'final' cannot be overridden by 'DeriveClass::func'
virtual void func(int param) override { cout << "DeriveClass::func. param = " << param <<endl; } };
由注释部分可以看出,基类的func函数使用Final进行限定后,派生类无法再重写改函数。
5.总结
C++11新增添的 override 和 final 说明符可以使得虚函数的继承更加明确和安全。遵循新的规则,可以增进代码的可读性,使用final可以更好的对派生和重写虚函数进行限制。
C++11学习笔记(5) —— override and final (转)的更多相关文章
- C++11 学习笔记 std::function和bind绑定器
C++11 学习笔记 std::function和bind绑定器 一.std::function C++中的可调用对象虽然具有比较统一操作形式(除了类成员指针之外,都是后面加括号进行调用),但定义方法 ...
- C++11学习笔记
C++11 1.long long新类型 2.列表初始化 int t=0; int t={0}; int t(0); int t{0}; 注意:如果我们使用列表初始化有丢失信息的风险,则编译器报错 l ...
- C++11之重写说明符override和final
关于 本文代码演示环境: win10 + vs2017 一个困扰 之前MFC用的多了,发现一个问题: 子类窗口的某个函数是否重载了基类的函数.解决办法是: 打开基类的代码,一个个排查. 这只是一个具体 ...
- PHP学习笔记三十【final】
<?php //final不能去修饰属性(变量) //如果希望类不希望被继承就可以使用final关键字 final class Person() { public function sayHi( ...
- linux0.11学习笔记(1)
公布软件包包括内容: bootimage.Z - 具有美国键盘代码的压缩启动映像文件: rootimage.Z - 以1200kB 压缩的根文件系统映像文件: linux-0.11.tar.Z- 内核 ...
- C++11学习笔记之三lamda表达式,std::function, std::bind
//lamda //first lamda [] {}; // second lamda []() //or no need () when paramater is null { std::cout ...
- 802.11学习笔记1-WIFI参数含义
研究下wifi参数的含义 #The word of "Default" must not be removed Default CountryRegion= CountryRegi ...
- Linux就该这么学11学习笔记
参考链接:https://i.cnblogs.com/EditPosts.aspx?opt=1 文件传输协议 一般来讲,人们将计算机联网的首要目的就是获取资料,而文件传输是一种非常重要的获取资料的方式 ...
- 【DirectX 11学习笔记】世界矩阵的理解-运动合成
最近在看龙书,写一下自己的学习理解,主要是物体运动的合成. 物体于局部坐标系内构建,每个物体拥有自己的局部坐标系以及相应的顶点矩阵A,并通过世界矩阵变换到唯一的世界坐标系. 物体在某时刻发生了位移和旋 ...
随机推荐
- 解决cocos2dx 打包lua环境搭建问题( ImportError: No module named Cheetah.Template)
将c++ 封装成lua调用时,显示一下错误: PYTHON_BIN not defined, use current python. generating userconf.ini... Genera ...
- I/O理解
I/O是什么 我的理解I/O就是用于读写的一个流 官方解释:I/O(英语:Input/Output),即输入/输出,通常指数据在内部存储器和外部存储器或其他周边设备之间的输入和输出. node中的io ...
- tensorflow目标检测API之训练自己的数据集
1.训练文件的配置 将生成的csv和record文件都放在新建的mydata文件夹下,并打开object_detection文件夹下的data文件夹,复制一个后缀为.pbtxt的文件到mtdata文件 ...
- rest_framework之status HTTP状态码
Django Rest Framework有一个status.py的文件 通常在我们Django视图(views)中,HTTP状态码使用的是纯数字,像400,404,200,304等,并不是那么很好理 ...
- jQuery获取动态添加的元素,live和on的区别
今天给大家说一下如果用jQuery获取动态添加的元素,通常如果你在网页上利用jQuery添加一个元素,那么用平常的jQuery获取元素的方法无效的获取不到的.可以用以下的方法获取动态元素!假设我们现在 ...
- 蓝桥--2n皇后问题(递归)--搬运+整理+注释
N皇后问题: #include <iostream> #include <cmath> using namespace std; int N; ];//用来存放算好的皇后位置. ...
- linux用户和用户组管理详解
Linux 用户和用户组管理 Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统. 用户的账号一方面可以帮助 ...
- 设置ubuntu12.04的dasher-自动隐藏,左上角
点击右上角的齿轮,--> “system setting”--“Appearance” 在“Look”标签中: Theme:Ambiance Launch icon size :32 选择桌面背 ...
- Centos7 install Openstack Juno (RDO) (转载)
原文地址:http://www.hdume.com/centos-7-0%E5%AE%89%E8%A3%85openstack/ 1.安装系统,Centos7镜像采用CentOS-7.0-1406-x ...
- selenium2元素定位Xpath和cssSelector
Selenium2中元素有以下几种定位方法, 常用的有Id,xpath, cssSelector XPATH介绍: XPATH是一种选择器 XPATH在firefox中用firepath验证 XP ...