c++11 override and final

来源:互联网 发布:windows字体怎么设置 编辑:程序博客网 时间:2024/05/17 23:52

1.简介

C++为我们提供了继承和虚函数的重写特性。 在派生类中,重写虚函数不强制要求使用 virtual 关键字,并且C++并没有要求强制检查虚函数的重写是否真正覆盖了基类的虚函数,因为在派生类中,也可以增添新的虚函数,以供下一级的派生类重写。由于检查的不够严谨,就有可能产生错误。

2.有可能产生的错误

最常见的错误就是派生类想要重写基类的虚函数,但是由于参数类型的不同,导致结果和预期不同,例如:

[cpp] view plain copy
  1. #include"stdafx.h"  
  2. #include<iostream>  
  3.   
  4. using namespace std;  
  5.   
  6. class BaseClass  
  7. {  
  8. public:  
  9.     BaseClass(){}  
  10.     ~BaseClass(){}  
  11. public:  
  12.     virtual void func(int param) { cout << "BaseClass::func. param = "  << param <<endl; }  
  13.     virtual void func2() const { cout<< "BaseClass::func2."<<endl;}  
  14. };  
  15.   
  16. class DeriveClass : public BaseClass  
  17. {  
  18. public:  
  19.     DeriveClass(){}  
  20.     ~DeriveClass(){}  
  21. public:  
  22.     virtual void func(float param) { cout << "DeriveClass::func. param = "  << param <<endl; }  
  23.     virtual void func2() { cout<< "DeriveClass::func2."<<endl;}  
  24. };  
  25.   
  26. int main()  
  27. {  
  28.     BaseClass* pBase = new BaseClass();  
  29.     pBase->func(1);  
  30.     pBase->func2();  
  31.   
  32.     cout<<endl;  
  33.   
  34.     DeriveClass* pDerive = new DeriveClass();  
  35.     pDerive->func(4);  
  36.     pDerive->func2();  
  37.   
  38.     cout<<endl;  
  39.   
  40.     BaseClass* pTest = new DeriveClass();  
  41.     pTest->func(5);  
  42.     pTest->func2();  
  43.   
  44.     cout<<endl;  
  45.   
  46.     system("pause");  
  47.     return 0;  
  48. }  

输出结果为


对于函数func,派生类和基类的参数类型不同,虽然函数的返回值和函数名相同,并使用了virtual进行虚函数的声明,但实际上派生类并没有重写基类的虚函数,而是定义了自己的虚函数。使用const 进行限定也是一样,在基类中func2 为 const 函数,而派生类没有 const 进行限定,因此,派生类也并没有重写基类的虚函数。 pTest 的输出结果和我们原本预期的并不相同,其调用的是基类的虚函数。由上图输出结果可以看出。

3. override

为了避免上述问题的发生,C++11增添了override, override并不是一个关键字,而是一个用于标记虚函数重写的标识符,使用override 标记的类成员函数表示我们希望其重写基类相对应的虚函数。如果没有重写,编译器会报错。例如:

[cpp] view plain copy
  1. class BaseClass  
  2. {  
  3. public:  
  4.     BaseClass(){}  
  5.     ~BaseClass(){}  
  6. public:  
  7.     virtual void func(int param) { cout << "BaseClass::func. param = "  << param <<endl; }  
  8.     virtual void func2() const { cout<< "BaseClass::func2."<<endl;}  
  9. };  
  10.   
  11. class DeriveClass : public BaseClass  
  12. {  
  13. public:  
  14.     DeriveClass(){}  
  15.     ~DeriveClass(){}  
  16. public:  
  17.     //error C3668: 'DeriveClass::func' : method with override specifier 'override' did not override any base class methods  
  18.     virtual void func(float param) override { cout << "DeriveClass::func. param = "  << param <<endl; }  
  19.   
  20.     //error C3668: 'DeriveClass::func2' : method with override specifier 'override' did not override any base class methods  
  21.     virtual void func2() override { cout<< "DeriveClass::func2."<<endl;}  
  22. };  

对DeriveClass 的两个成员函数使用了 override ,编译器知道我们期望重写基类的虚函数,但是由于基类并没有相匹配的虚函数,因此编译出错,出错信息如上述注释部分所示。

4.final

在一些情况下,我们并不希望某个成员函数再被任何派生类所继承,在java语言中,有final来进行限定,C++11也提供了 final (同 override一样不是关键字,只是特殊的标识符)。通过使用final对虚函数的限定,任何子类不能重写该函数,例如:

[cpp] view plain copy
  1. class BaseClass  
  2. {  
  3. public:  
  4.     BaseClass(){}  
  5.     ~BaseClass(){}  
  6. public:  
  7.     virtual void func(int param) final { cout << "BaseClass::func. param = "  << param <<endl; }  
  8. };  
  9.   
  10. class DeriveClass : public BaseClass  
  11. {  
  12. public:  
  13.     DeriveClass(){}  
  14.     ~DeriveClass(){}  
  15. public:  
  16.     //error C3248: 'BaseClass::func': function declared as 'final' cannot be overridden by 'DeriveClass::func'  
  17.     virtual void func(int param) override { cout << "DeriveClass::func. param = "  << param <<endl; }  
  18.   
  19. };  

由注释部分可以看出,基类的func函数使用Final进行限定后,派生类无法再重写改函数。


5.总结

C++11新增添的 override 和 final 说明符可以使得虚函数的继承更加明确和安全。遵循新的规则,可以增进代码的可读性,使用final可以更好的对派生和重写虚函数进行限制。

原创粉丝点击