📌从字面意思上,是覆盖的意思,实际上在C++中它是覆盖了一个方法并且对其重写,从而达到不同的作用.
C++ override关键字
override关键字的作用
如果派生类在虚函数声明时使用了override描述符,那么该函数必须重载其基类中的同名函数,否则代码将无法通过编译。
C++中的关键字override(重载)用于在派生类中声明一个函数与其基类中同名函数的关系。当派生类在虚函数声明时使用override描述符时,需要重载其基类中的同名函数,否则编译器将会提示错误。
这是因为在C++中,虚函数的定义与函数重载非常相似。虚函数定义的方式是使用关键字virtual在函数声明中进行声明,同时可以通过重载来指定函数的行为。如果派生类重载了基类中的同名函数,则该函数将成为派生类中的虚函数,可以通过调用基类中的函数来实现该函数的功能。如果派生类未重载基类中的同名函数,则该函数将被认为是虚函数,并且无法直接访问。这样就保证了代码的灵活性和可维护性,同时也提高了代码的可读性和可理解性。因此,在C++中,override关键字是非常重要的一个特性,对于实现灵活的类型重载和抽象函数的使用非常有帮助。
This is because in C++, virtual functions are defined and overloaded in a similar way to function overloading. The definition of virtual function is made using the keyword “virtual” in the function declaration, and it can be overloaded to specify the behavior of the function. If a derived class overrides the same function in the base class, the function will become a virtual function in the derived class, and it can be called to implement the function’s functionality. If the derived class does not override the same function in the base class, the function will be considered a virtual function and cannot be directly accessed. This ensures flexibility and maintainability of the code, as well as improving its readability and understandability. Therefore, in C++, the override keyword is a very important feature that is helpful for implementing flexible type overload and abstract function.
- 注意
在C++中,
override
关键字是可选的,用于显式地指示编译器一个成员函数(通常是虚函数)是重写了基类中的同名函数。如果你不使用override
关键字,编译器仍然会执行重写行为,只要函数的签名与基类中的虚函数相匹配。
override的使用条件
- 基类成员函数为虚函数(virtual)
- 派生类中重写该成员函数
- 函数签名必须完全匹配:派生类中的函数必须与基类中被重写的虚函数在函数签名上完全匹配,包括函数名、参数类型、常量性(const)和引用修饰符(&或&&)。否则,编译器将不会认为这是一个重写,而是一个新的函数。
- 返回类型可以协变:在C++中,重写虚函数的返回类型可以是基类虚函数返回类型的子类。这被称为返回类型协变。例如,如果基类虚函数的返回类型是
Base*
或Base&
,那么派生类中重写的函数的返回类型可以是Derived*
或Derived&
,其中Derived
是Base
的子类。 - 只能重写公有和保护的虚函数:你只能重写基类中的公有和保护的虚函数。私有虚函数不能在派生类中被重写,因为它们在派生类中不可见。
- 不能重写非虚函数:
override
关键字只能用于重写虚函数。如果你尝试使用override
关键字重写一个非虚函数,编译器会报错。 - 不能改变虚函数的默认参数:虽然C++允许你在派生类中为重写的虚函数提供不同的默认参数,但这通常是一个坏主意,因为它可能会导致意外的行为。当你通过基类指针或引用调用虚函数时,将使用基类版本的默认参数,而不是派生类版本的默认参数。
- A virtual member function in a base class.
- Override the virtual member function in the derived class.
- The function signature must match completely. The derived class function must be a completely new function that matches the signature of the virtual member function in the base class, including the function name, parameter type, const-ness, and reference modifiers (& or &&). Otherwise, the compiler will not consider it a re-implementation, but rather a new function.
- The return type of the derived class function can be a sub-type of the return type of the base class virtual member function. For example, if the base class virtual member function is
Base*
orBase&
, the derived class function can be a sub-type ofDerived*
orDerived&
, whereDerived
is a subclass ofBase
. - You can only override public and protected virtual functions in the base class. Private virtual functions cannot be overridden in the derived class, because they are not visible in the derived class.
- You cannot override a non-virtual member function. Although you can provide different default parameters for the overridden virtual member function in the derived class, this is usually a bad idea because it can lead to unexpected behavior. When you use a pointer or reference to call the virtual member function in the base class, it will use the base class version of the default parameter, not the derived class version.
使用override 关键字的好处
- 程序员的意图更清晰:通过在派生类中使用
override
关键字,可以清楚地表明该函数是对基类中的虚函数的重写。这使得代码更易读,更易理解。 - 让编译器发现一些错误:如果你标记了一个函数为
override
,但它并没有真正重写任何基类中的函数,编译器会报错。这可以帮助你捕获一些可能的错误,例如函数签名的误差。 - 提高代码的维护性:如果基类的虚函数在未来发生改变(例如参数类型或数量的改变),但是派生类中的重写函数没有相应地改变,那么使用了
override
关键字的函数会在编译时报错,这样可以及时发现并修复问题。 - 提高代码的稳定性:使用
override
关键字可以确保当基类的虚函数接口改变时,所有的派生类都会得到更新,否则编译器会报错。这可以防止因接口改变而导致的运行时错误。 - 提高代码的可读性和可理解性:
override
关键字明确地表明了函数是重写了基类中的函数,这对于阅读和理解代码非常有帮助。
- Programmer’s intent is clearer: By using the
override
keyword in a derived class, it is clear that the function is a re-write of the virtual function in the base class. This makes the code easier to read and understand. - Allows the compiler to discover some errors: If a function marked with the
override
keyword does not actually override any functions in the base class, the compiler will report an error. This can help you catch some potential errors, such as differences in function signatures. - Improves code maintainability: If the base class virtual function interface changes in the future, but the overridden function in the derived class does not correspondingly change, then the function marked with the
override
keyword will report an error during compilation, which can be used to catch and fix the problem in time. - Improves code stability: Using the
override
keyword can ensure that all derived classes will be updated when the base class virtual function interface changes, otherwise the compiler will report an error. This can prevent runtime errors caused by interface changes. - Improves code readability and understandability: The use of
override
keyword clearly indicates that the function is a re-write of the function in the base class, which is very helpful for reading and understanding the code.
C++ override 关键字的来源
C++的override
关键字是在C++11标准中引入的。在C++11之前,C++并没有提供一种明确的方式来表明一个函数是重写了基类中的虚函数。这可能会导致一些错误,例如如果派生类中的函数签名与基类中的虚函数不完全匹配,那么这个函数可能不会被视为重写,而编译器也不会报错。
为了解决这个问题,C++11引入了override
关键字。通过在派生类中使用override
关键字,可以清楚地表明该函数是对基类中的虚函数的重写。如果这个函数并没有真正重写任何基类中的函数,编译器会报错。
这个特性使得C++的代码更加安全,更易于维护。它可以帮助程序员避免一些常见的错误,例如误打误写导致的函数签名不匹配,以及在基类中添加或修改虚函数时忘记更新派生类中的函数等。
使用示例
#include<iostream> using namespace std; class Base { public: // 虚函数 virtual void statmem() { cout << "基类函数" << endl; } }; class Derived :public Base { public: // override 重写 // final 不允许后续其它类覆盖 void statmem() override final { cout << "派生类函数" << endl; } }; // 多态 int main() { Base base; Derived derived; base.statmem(); // 基类函数 derived.statmem(); // 派生类函数 // 将derived的Base部分拷贝给base2 Base base2(derived); base2.statmem(); // 基类函数 // 动态绑定只有当我们通过指针或引用调用虚函数时才会发生 // 基类调用它的派生类函数 Base *base3 = &derived; base3->statmem(); // 派生类函数 Base *base4(&derived); base4->statmem(); // 派生类函数 // 派生类调用它的基类函数 Derived derived1; derived.Base::statmem(); // 基类函数 Derived *derived2 = &derived; derived2->Base::statmem(); // 基类函数 return 0; }
结语
在我们的编程学习之旅中,理解是我们迈向更高层次的重要一步。然而,掌握新技能、新理念,始终需要时间和坚持。从心理学的角度看,学习往往伴随着不断的试错和调整,这就像是我们的大脑在逐渐优化其解决问题的“算法”。
这就是为什么当我们遇到错误,我们应该将其视为学习和进步的机会,而不仅仅是困扰。通过理解和解决这些问题,我们不仅可以修复当前的代码,更可以提升我们的编程能力,防止在未来的项目中犯相同的错误。
我鼓励大家积极参与进来,不断提升自己的编程技术。无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力。