博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

final override

Posted on 2017-11-28 11:28  bw_0927  阅读(161)  评论(0)    收藏  举报

http://blog.csdn.net/crayondeng/article/details/18563121

 

 

C++借由虚函数实现运行时多态,但C++的虚函数又很多脆弱的地方:

  • 无法禁止子类重写它。可能到某一层级时,我们不希望子类继续来重写当前虚函数了。
  • 容易不小心隐藏父类的虚函数。比如在重写时,不小心声明了一个签名不一致但有同样名称的新函数。

Effective C++: Item 33一文中详细讨论了父类名称隐藏的问题。

C++11提供了final来禁止虚函数被重写/禁止类被继承,override来显示地重写虚函数。 这样编译器给我们不小心的行为提供更多有用的错误和警告。

struct Base1 final { };     
struct Derived1 : Base1 {};         // 编译错:Base1不允许被继承

struct Base2 {
    virtual void f1() final;                  //virtual和final可以并存; 最后一级虚函数
    virtual void f2();
};
struct Derived2 : Base2 {
    virtual void f1();              // 编译错:f1不允许重写
    virtual void f2(int) override;  // 编译错:父类中没有 void f2(int)
};

 

使用场合(override):

第一种情况是你想覆写一个基类的函数,但是不小心参数不匹配或者名字拼错,结果导致写了一个新的虚函数。这时候如果你加上override关键字,编译器会帮你发现与基类函数不匹配从而给出编译错误的提示。

第二种,在使用别人的函数库,或者继承了别人写的类时,你想写一个新函数,但是可能碰巧与原来基类的函数名称一样,这样就会被编译器(以及其他人)误认为要重写基类的函数。

如果大家都养成习惯重写基类虚函数时都加上override,别人在看到你的代码时就知道你当前的函数是否想重写基类里面的函数,也就容易发现你这个无意中重载的Bug。

==================================

 

两者都是用在对于继承体系的控制

final

用来标明被这个修饰符修饰的class/struct或者虚函数已经是最终版本,无法被进一步继承.

  1. class Base final    #修饰类
  2. {  
  3. public:  
  4.     virtual void test(){}  
  5. };  
  6.   
  7. class D1:public Base  
  8. {  
  9.     void test(){}  
  10. };  

 

如这个例子,Base类被final修饰,表示其已经无法被继承,编译器会提示如下错误:error C3246: ‘D1′ : cannot inherit from ‘Base’ as it has been declared as ‘final’

 

再看另外一个例子:

  1. class Base  
  2. {  
  3. public:  
  4.     virtual void test(){}  
  5. };  
  6.   
  7. class D1:public Base  
  8. {  
  9.     void test() final {}    #修饰虚函数
  10. };  
  11.   
  12. class D2 :public D1  
  13. {  
  14.     void test(){}  
  15. };  

 

此时虚函数test在D1被final标识,已经表明其是最终版本,无法进一步继承.

override

override关键字用来表示:子类中的函数一定是重载自基类的同名同性质的虚函数或者纯虚函数,否则无法被编译.

[cpp] view plain copy
 
  1. class Base  
  2. {  
  3. public:  
  4.     virtual void test(){}  
  5.     virtual void test2(int i) {}  
  6.     virtual void test3() const {}  
  7. };  
  8.   
  9. class D1:public Base  
  10. {  
  11.     void test() override {}  //编译正确  
  12.     void test2(float i) override {} //编译错误,参数不一致  
  13.     void test3() override {} //编译错误,函数常量性不一致  
  14.     void test4() override {} //编译错误,并不是重载父类虚函数  
  15. };  

需要注意的一点是,final和override两者很有可能在C++ 98的代码里面被程序员大量的用在其他地方命名,因此C++ 11为了保持和之前代码的兼容性,所以这两个标记只有在修饰class/struct和函数的时候,才会被当成关键字

也就是说,在其他地方依然可以使用这两个字符命名成变量/函数/类/结构体.

比如:

  1. class Base  
  2. {  
  3. public:  
  4.     virtual void test()  
  5.     {  
  6.         int final = 1;  
  7.     }  
  8.     virtual void test2(int i) {}  
  9.     virtual void test3() const {}  
  10.     virtual void override();  
  11. };  


这是正确的.