管理虚方法
通过学习多态的知识,我们已经了解到对于派生类来说很多时候会覆盖它继承的虚函数,覆盖时要求派生类中重新定义函数的返回值类型、函数名、参数与基类虚函数的对应内容一致,否则在派生类中创建新的函数,不能达到覆盖的目的,此时编译并不会报错。若想通过编译器发现这样的错误,C++11新标准中可以使用override关键字来说明派生类中的虚函数,这样就使得覆盖的意图更加清晰,并且也可以借助于编译器检查是否完成了覆盖。使用override的方法是在派生类中虚函数形参列表后添加override关键字。
下列代码描述了声明函数具有override属性的方法,具体内容如下所示:
class Base{ //定义基类
public:
virtual void func1(int); //声明虚函数
virtual void func2();
void func3();
};
class Derived:public Base //定义派生类
{
public:
void func1(int) override; //正确,使用override说明覆盖基类同名虚函数
void func2(float) override; //错误,函数参数与基类函数不同,不可覆盖
void func3() override; //错误,不可覆盖非虚函数
};
上述代码中,派生类函数func1()后面的override使用正确,因为它要覆盖的是基类中返回值类型、函数名、参数完全相同的虚函数。func2()后面使用override时,编译器会报错,因为在基类中同名虚函数func2()是无参函数,派生类中的func2()是重定义而不是改写。派生类中的func3()后面使用override也会报错,因为基类中的同名函数不是虚函数。override只可以对虚函数覆盖进行检查。
除了override,C++11新标准还增加了防止基类被继承和防止派生类重写函数的功能。这是由特殊的标识符final来完成的,其方法是在类名后或函数参数后添加关键字final。
下述代码描述了使用final修饰类的方法,内容如下所示:
class NoDerived final //定义final类,不可作为基类派生新类
{
…
};
class Base{ //定义普通类,可作为基类
…
};
//正确,定义final类Last,不可派生新类,该类派生自Base
class Last final:public Base
{
…
};
class Error1:public NoDerived //错误,不可通过NoDeived类派生新类
{
};
class Error2:public Last //错误,不可通过Last类派生新类
{
…
};
从上述代码可以看出,被final修饰的类,不可作为基类派生新类。final除了修饰类外,还可以修饰某个函数。如果已经把函数定义成final,则之后任何尝试覆盖该函数的操作都将发生错误。
下述代码演示了使用final修饰函数的方法,具体内容如下所示:
class Base{ //基类定义
public:
virtual void func1(int) final; //虚函数,不可被覆盖
virtual void func2();
};
class Derived:public Base //派生类定义
{
public:
void func1(int); //错误,基类中的同名虚函数已定义为final
void func2() override; //正确,覆盖基类同名虚函数
};
上述代码中,基类中的虚函数func1()使用final修饰,阻止了派生类重写这个函数。
需要注意的是,override和final都不是C++语言的关键字,它们只是技术上的标识符,只有在类似上述代码中,对类和函数性质进行说明时才有特殊意义,用在其它地方仍然是有效标识符。