C++ override和final的用法(非常详细,附带实例)
不像其他类似的编程语言,C++ 没有特定的语法来声明接口类型(基本上只在类中声明纯虚方法),并且在声明虚方法方面有一定的缺陷。
在 C++ 中,虚方法用关键字 virtual 声明。但是,在派生类中声明覆盖时,关键字 virtual 是可选的,这在处理大型类或层次结构时可能会导致混淆。你可能需要在整个层次结构中追溯到基类以确定函数是否是虚函数。另一方面,有时确保虚函数甚至派生类不能被重写或者进一步继承是必要的。
本节我们将学习使用 override 和 final 关键字声明虚函数和类。学习本文,读者要熟悉 C++ 中继承和多态,以及抽象类、纯虚说明符、虚方法和覆盖方法的概念。
1)在派生类中声明应该覆盖基类中的虚函数的虚函数时,建议使用 virtual 关键字。
2) 始终在虚函数声明或定义部分之后使用 override 特殊标识符:
为了保证函数不能被进一步覆盖或者类不能被进一步继承,请使用 final 特殊标识符:
1) 在虚函数声明或定义的声明符之后用 final 防止在派生类中对函数进行进一步覆盖:
2) 在类声明中的类名后用 final 防止类被进一步继承:
注意,override 和 final 关键字都是特殊标识符,仅在成员函数声明或定义中有意义。它们不是保留关键字,所以仍然可以在代码的其他任何地方用作自定义标识符。
使用 override 标识符有助于编译器检查虚方法是否覆盖另一个虚方法,如以下示例所示:
另一个特殊标识符 final 用在成员函数声明或定义中,表示该函数是虚函数并且不能在派生类中被覆盖。如果派生类试图覆盖该虚函数,编译器会报错:
final 标识符也可以在类的声明中使用,表示该类不能被继承:
由于 override 和 final 在定义中使用时都具有特殊含义,并且实际上不是系统保留关键字,因此你仍然可以在 C++ 代码中的其他任何地方使用它们。这可以确保用 C++11 之前的版本编写的现有代码不会因使用它们作为标识符而损坏:
在 C++ 中,虚方法用关键字 virtual 声明。但是,在派生类中声明覆盖时,关键字 virtual 是可选的,这在处理大型类或层次结构时可能会导致混淆。你可能需要在整个层次结构中追溯到基类以确定函数是否是虚函数。另一方面,有时确保虚函数甚至派生类不能被重写或者进一步继承是必要的。
本节我们将学习使用 override 和 final 关键字声明虚函数和类。学习本文,读者要熟悉 C++ 中继承和多态,以及抽象类、纯虚说明符、虚方法和覆盖方法的概念。
C++ override和final的使用方式
为了确保在基类和派生类中正确地声明虚方法,同时提高可读性,请遵循以下原则:1)在派生类中声明应该覆盖基类中的虚函数的虚函数时,建议使用 virtual 关键字。
2) 始终在虚函数声明或定义部分之后使用 override 特殊标识符:
class Base { virtual void foo() = 0; virtual void bar() {} virtual void foobar() = 0; }; void Base::foobar() {} class Derived1 : public Base { virtual void foo() override = 0; virtual void bar() override {} virtual void foobar() override {} }; class Derived2 : public Derived1 { virtual void foo() override {} };声明符是函数类型中除去返回类型的部分。
为了保证函数不能被进一步覆盖或者类不能被进一步继承,请使用 final 特殊标识符:
1) 在虚函数声明或定义的声明符之后用 final 防止在派生类中对函数进行进一步覆盖:
class Derived2 : public Derived1 { virtual void foo() final {} };
2) 在类声明中的类名后用 final 防止类被进一步继承:
class Derived4 final : public Derived1 { virtual void foo() override {} };
C++ override和final的工作原理
override 关键字的用法很简单,在虚函数的声明或定义中,它可以保证函数确实覆盖了一个基类函数,否则,编译器会报错。注意,override 和 final 关键字都是特殊标识符,仅在成员函数声明或定义中有意义。它们不是保留关键字,所以仍然可以在代码的其他任何地方用作自定义标识符。
使用 override 标识符有助于编译器检查虚方法是否覆盖另一个虚方法,如以下示例所示:
class Base { public: virtual void foo() {} virtual void bar() {} }; class Derived1 : public Base { public: void foo() override {} // for readability use the virtual keyword virtual void bar(char const c) override {} // error, no Base::bar(char const) };如果不存在 override 标识符,则 Derived1 类的虚方法 bar(char const) 将不是覆盖方法,而是来自 Base 的 bar() 的重载。
另一个特殊标识符 final 用在成员函数声明或定义中,表示该函数是虚函数并且不能在派生类中被覆盖。如果派生类试图覆盖该虚函数,编译器会报错:
class Derived2 : public Derived1 { virtual void foo() final {} }; class Derived3 : public Derived2 { virtual void foo() override {} // error };
final 标识符也可以在类的声明中使用,表示该类不能被继承:
class Derived4 final : public Derived1 { virtual void foo() override {} }; class Derived5 : public Derived4 // error { };
由于 override 和 final 在定义中使用时都具有特殊含义,并且实际上不是系统保留关键字,因此你仍然可以在 C++ 代码中的其他任何地方使用它们。这可以确保用 C++11 之前的版本编写的现有代码不会因使用它们作为标识符而损坏:
class foo { int final = 0; void override() {} };尽管前面我建议在重写虚方法的声明中同时使用 virtual 和 override,但是 virtual 关键字是可选的,可以省略以缩短声明。override 标识符的存在应该是以表明该方法是虚方法,这是个人喜好问题,并不影响语义。