【C++11】final, override,重载,重写覆盖,重写隐藏

1:final, override的作用

1:final的作用:修饰类或成员函数

修饰类时: 表示本类禁止被继承;
修饰成员函数:
    virtual成员函数:表示不允许子类重写覆盖,但可以重写隐藏
    非virtual成员函数:表示不允许子类重写隐藏;

2:override:用于标示虚函数,明确说明这是重写覆盖父类的同名函数,避免造成重写隐藏的情况;

2: 示例代码

/ final的用法: 用于标识类或成员函数,禁止子类继承或重写
// 具体是禁止重写隐藏还是重写覆盖得看成员函数是否有virtual关键字修饰
// 1, final 修饰类
// 用final修饰,意味着继承该类会导致编译错误
class Hello final 
{
    ...
}

/* 2, final 修饰成员方法,可以是虚函数,也可以是普通成员函数, 虚函数则表示不允许子类重写覆盖,但经测试证明仍允许重写隐藏, 普通成员函数则表示不允许子类重写隐藏: */
class A
{
public:
    virtual void f(int) final {}
};

class B : public A
{
public:
    /*
    这样将会导致错误,因为父类声明了该虚函数为final,
    即表示不允许子类重写覆盖;
    */
    // virtual void f(int){}

    /* 正确,这个函数与上面那个函数是互相独立的,不被认为是重写覆盖, 而是重写隐藏,这种情况要好好注意 */
    virtual void f(){} 
    virtual void f(double){} // 正确,原因同上
};
// 2 override的用法
// override只能用于标识虚函数,不能是普通成员函数, 比如:
class A
{
public:
    virtual void f(int){}
    void g(){};
};

class B : public A
{
public:
    /*
    明确表示这个函数为的是重写覆盖父类的f(int);虚函数的, 
    如果可能发生错误导致可能的重写隐藏的话编译时就报错
    */
    virtual void f(int) override {} 

    /* 像这种形式就会导致编译时报错,因为这样不是重写覆盖, 而是重写隐藏,重写覆盖要求函数签名是一样的; */
    // virtual void f() override {} 

    /* 错误,因为override只能用于修饰虚函数,g();不是虚函数, 不可以使用override; */
    // void g() override {} 

};

另一方面,如果需要一个函数永远不能被重写覆盖(顺着继承层次往下都不能被重写覆盖),可以把该函数标识为final,在基类中和派生类中都可以这么做。如果是在派生类中,我们可以同时使用override和final标识符。

class B 
{
public:
   virtual void f(int) 
   {
       std::cout << "B::f" << std::endl;
   }
};

class D : public B
{
public:
   virtual void f(int) override final 
   {
       std::cout << "D::f" << std::endl;
   }
};

class F : public D
{
public:
   virtual void f(int) override
   {
       std::cout << "F::f" << std::endl;
   }
};

3:区分重载(overload)、重写隐藏、和重写覆盖(override) 注:

参考资料来源:http://www.voidcn.com/article/p-ccojqjul-beg.html
注: 原文单纯的区分重载、隐藏、和覆盖,有点混乱,这里我做了个人的注解:
成员函数中分为重载(overload)和重写(override)
而重写包括重写隐藏重写覆盖(常说override更多指的是这个)

类成员函数的重载(overload)、重写隐藏、和重写覆盖(override)区别
a.成员函数被重载(overload)的特征:
 (1)相同的范围(在同一个类中);
 (2)函数名字相同;
 (3)参数不同;
 (4)virtual关键字可有可无。
 (5)对(1)的补充:不同类中形成的两种重载(overload):
     5.1 如下代码:
// 5.1
class B 
{
public:
   virtual void f(short) 
   {
       std::cout << "B::f" << std::endl;
   }
};

class D : public B
{
public:
   virtual void f(int) 
   {
       std::cout << "D::f" << std::endl;
   }
};

// 5.2
class B 
{
public:
   virtual void f(int) const 
   {
       std::cout << "B::f " << std::endl;
   }
};

class D : public B
{
public:
   virtual void f(int) 
   {
       std::cout << "D::f" << std::endl;
   }
};
b.重写覆盖(override)是指派生类函数覆盖基类函数,特征是:
 (1)不同的范围(分别位于派生类与基类);
 (2)函数名字相同;
 (3)参数相同;整个函数签名一样;
 (4)基类函数必须有virtual关键字。
// 重写覆盖示例
class A
{
public:
    void f(int)  
    {
        cout << "A" << endl;
    }
};

class B : public A
{
public:
    virtual void f(int){}; 
};
c.重写“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
 (1)如果派生类的函数与基类的函数同名,但是参数不同。
    此时,不论有无virtual关键字,基类的函数将被隐藏
   (注意别与重载混淆)。但注意如果加上virtual则
   通过父类型指针或引用访问不用类名::的形式访问也可以访问;
   如下例:
 (2)如果派生类的函数与基类的函数同名,并且参数也相同,
     但是基类函数没有virtual关键字。此时,
     基类的函数被隐藏(注意别与覆盖混淆)
// 重写隐藏示例 
#include <iostream>
#include <cstring>

using namespace std;

class A
{
public:
    void hello(){cout<<"A hello"<<endl;}
    virtual void hello(int i){cout<<"A hello int"<<endl;}
};

class B:public A
{
public:
    // B中的hello()隐藏了A中的hello(int)
    void hello() const{cout<<"B hello"<<endl;} 
};

// const导致重载时的隐藏问题,解决办法,在B中重新定义hello(int)函数
int main()
{
    B b;
    b.hello();
    // b.hello(1); // error
    b.A::hello(1);  // 这种情况得通过类名::的形式访问

    A *p = new B;
    // 通过父类指针类型来访问还是正确,这种情况不用类名::的形式访问
    p->hello(2); 
}
// 注意分清楚重载(overload)和重写隐藏以及重写覆盖(override)
// 重写隐藏:
    class A
    {
    public:
        void test(){};
    }
    class B : public A
    {
    public:

    /* 
    因为不是虚函数,同名则会导致重写隐藏父类的,这是要调用子类中
    要调用父类的test()必须通过A::test();的形式进行调用;
    */
        void test(int i){} 
    };


    /* 另外注意: 一个函数中是否有const修饰函数也会造成重载,但不属于重写隐藏 或重写覆盖,是两个不同的函数, 如下例: */
    class B
    {
    public:
        virtual void test()const{};
    };
    class D : public B
    {
    public:
        virtual void test(){}; 
    /* 这个函数没有const修饰,因此这个函数尽管有多态的性质, 但是是属于两个函数,这是因为成员函数的隐形参数this的原因: 一个是this,一个是const this的类型; */
    };

小结:

1)分清楚overload, 和override;
2)注意重载与重写覆盖,重写隐藏的条件;

参考资料:
http://blog.jobbole.com/44015/
http://www.voidcn.com/article/p-cakzonpt-bky.html
http://www.voidcn.com/article/p-ccojqjul-beg.html

相关文章
相关标签/搜索