翻译《有关编程、重构及其他的终极问题?》——24.override和final关键字应该成为你的新朋友

本文探讨了C++11中引入的override和final关键字如何帮助避免继承结构中的虚函数重载错误。通过一个实际案例,展示了如何使用这两个关键字改进代码质量和维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

翻译《有关编程、重构及其他的终极问题?》——24.override和final关键字应该成为你的新朋友

标签(空格分隔): 翻译 技术 C/C++
作者:Andrey Karpov
翻译者:顾笑群 - Rafael Gu
最后更新:2017年04月26日


24.override和final关键字应该成为你的新朋友

下面这段代码来自MFC库。PVS-Studio检查到的错误描述为:V301 Unexpected function overloading behavior. See first argument of function ‘WinHelpW’ in derived class ‘CFrameWndEx’ and base class ‘CWnd’(译者注:大意为异常的函数重载行为,请参看‘CFrameWndEx’子类和‘CWnd’基类‘WinHelpW’函数的第一个参数)。

class CWnd : public CCmdTarget {
  ....
  virtual void WinHelp(DWORD_PTR dwData,
                       UINT nCmd = HELP_CONTEXT);
  ....
};
class CFrameWnd : public CWnd {
  ....
};
class CFrameWndEx : public CFrameWnd {
  ....
  virtual void WinHelp(DWORD dwData,
                       UINT nCmd = HELP_CONTEXT);
  ....
};

解释
当你重载一个虚函数时,在在符号差异上是比较容易犯错的,比如在子类中定义一个与基类函数看似无关联的新函数,在这种情况下,这会产生各种错误提示:
1. 在重载的函数中,参数使用了其他类型。
2. 在重载的函数中有不同数量的参数个数,这对于有多个参数的情况非常重要。
3. 在重构的函数中const关键字用法不同。
4. 基类函数并非虚函数,这种情况假定子类的函数会重载基类的对应函数,但实际上却屏蔽了它。

当程序员改变了整个继承结构中的虚函数的各种符号而忘了修改其对应的子类函数时,相关于参数类型和质量修改的错误就会在已知代码中出现。

这个错误特别容易在把移动移植到64位平台的情况下发生,比如用DWORD_PTR替换DWORD类型,用LONG_PTR替换LONG类型等。这里查看更多细节。这其实就是我们上面错误发生的情况。

即使在上面错误的情况下,在32位系统下仍然能正常工作,因为DWORD和DWORD_PTR都是和unsigned long意义相同的(译者注:即unsigned long的别名);但在64位版本上就会发生错误,因为DWORD_PTR是和unsigned __int64相同意义的。

正确的代码

class CFrameWndEx : public CFrameWnd {
  ....
  virtual void WinHelp(DWORD_PTR dwData,
                       UINT nCmd = HELP_CONTEXT) override;
  ....
};

建议
现在,我们有了新的方法来防止我们犯下前面所说的错误,在C++ 11中增加了两个新的关键字:

  • Override - 表示修饰的函数重载了基类中的一个虚函数
  • Final - 表示子类中不能(再)重载这个函数

这里我们对override关键字感兴趣,它告诉编译器去检查对应的虚函数是否真的重载了基类中的对应函数,如果没有就会报错。

如果override关键字在CFrameWndEx类的WinHelp中被使用了,我们在编译64位版本的应用程序时就会得到一个错误,这样,这个错误其实就能尽早的被发现(译者注:然后被修正)。

当使用可重载的虚函数时,请无比使用override关键字(或者final关键字)。更多关于override和final关键字的知识可以看下面:

### 回答1: override关键字表示当前函数是一个覆盖基类函数的函数,它会检查当前函数的函数签名是否与基类的函数签名一致,如果不一致则会编译错误。使用override关键字可以更好地组织代码,并且可以防止一些继承时的错误。 final关键字可以用于类、类成员函数变量,表示它们是不可继承、覆盖或修改的。使用final关键字可以保护代码的完整性安全性,防止其他代码对其进行修改。 在定义类成员函数时,可以同时使用overridefinal关键字。这样可以确保该函数在继承时不会被覆盖或修改,同时也保证了该函数是一个覆盖基类函数的函数。 应该在以下情况下使用overridefinal关键字: - 当需要覆盖基类函数时,应该使用override关键字。 - 当需要保护代码完整性安全性时,应该使用final关键字。 - 当需要同时满足上述两种情况时,可以同时使用overridefinal关键字。 需要注意的是,overridefinal关键字只能用于虚函数,因为只有虚函数才会涉及到覆盖继承的问题。 ### 回答2: override关键字用于标记派生类中的成员函数,指示该函数是对基类中的虚函数进行覆盖。它用于确保派生类中的函数与基类中的虚函数具有相同的函数签名返回类型。如果在派生类中使用了override关键字,但实际上没有覆盖基类中的虚函数,编译器将产生一个错误。 final关键字用于指示类、函数或者变量是“终态”的,不能被继承、重写或重新赋值。final修饰的类不能有子类,final修饰的函数不能被子类重写,final修饰的变量则不允许再次赋值。 应该在以下情况下使用override关键字: 1. 派生类需要重写基类的虚函数以实现多态。 2. 需要确保派生类中的函数与基类中的函数具有相同的函数签名返回类型。 应该在以下情况下使用final关键字: 1. 不希望某个类被继承。 2. 不希望某个函数被重写。 3. 不希望某个变量被重新赋值。 在定义类成员函数时,可以同时使用overridefinal关键字。当一个成员函数在基类中被声明为虚函数时,可以在派生类中使用override关键字来显式地标识该函数为虚函数的重写。而final关键字可以用于在派生类中阻止进一步的重写。但需要注意的是,如果将一个函数同时标记为overridefinal,则将产生编译错误,因为这两个关键字具有冲突的含义。 ### 回答3: override关键字的作用是告诉编译器,当前的函数重写了父类中的同名虚函数。当父类中定义了一个虚函数,并且派生类中想要对该函数进行重写时,使用override关键字可以确保函数签名父类中的虚函数一致,以避免错误的重写。 final关键字的作用是禁止派生类对某个函数进行重写。当想要确定某个函数在整个继承层次中不可被重写时,可以使用final关键字。这样可以防止派生类对该函数的修改,从而增加代码的可预测性稳定性。 应该在以下情况下使用override关键字:当派生类需要对父类虚函数进行重写时,为了确保重写正确,可以使用override关键字。可以帮助程序员更好地理解代码,并提供编译错误指示,用于调试维护。 应该在以下情况下使用final关键字:当某个函数在父类中已经达到了最终的实现,不希望被派生类更改时,可以使用final关键字。可以增加代码的可维护性,确保函数的稳定性一致性。 对于类成员函数的定义,overridefinal关键字不能同时使用。因为override关键字是用于指示重写,而final关键字是用于指示禁止重写。这两个关键字的作用是互斥的。因此,在类成员函数的定义过程中,应该根据需要选择使用override关键字final关键字
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值