示例:
不加override
#ifndef __OVERRIDE__HH_
#define __OVERRIDE__HH_
class base
{
public:
virtual int getValue()
{
return 10;
}
};
class derived :public base
{
public:
int getValue()const
{
return 200;
}
};
#endif
override.cpp
#include "override.h"
#include<memory>
#include<iostream>
int main()
{
std::shared_ptr<base> pBase = std::shared_ptr<base>(new derived);
int test = pBase->getValue();
std::cout<<test<<std::endl;
return 0;
}
编译运行:
在上述示例中,derived
类试图重写基类base
的虚函数getValue
,但它没有使用override
关键字,也没有显式地指明该函数是对基类虚函数的重写。这种情况下,编译器并不会发出警告或错误。
问题是,derived
类中的foo
函数的参数列表或返回类型与基类中的虚函数是否匹配是开发人员自己的责任。如果开发人员犯了错误,如参数列表不匹配或返回类型不一致,就会导致函数并没有真正地重写基类函数,而是在派生类中重新定义了一个新的函数。
这可能会导致预期之外的行为和错误,而且这种问题在编译时无法捕获。程序可能会以不正确的方式进行运行,而开发人员在调试时可能很难意识到问题的根源。
执行的结果不是20而是是10,很显然derived没有实现基类的虚方法getValue,而是重新写了一个函数getValue(带了const关键字,const作为函数签名的一部分)。
加上override关键字:
#ifndef __OVERRIDE__HH_
#define __OVERRIDE__HH_
class base
{
public:
virtual int getValue()
{
return 10;
}
};
class derived :public base
{
public:
int getValue()const override
{
return 200;
}
};
#endif
编译报错:
原因是加了override则表示是重写基类的虚函数,但是加了const关键字和基类声明的getValue函数签名冲突。
去掉关键字const:
#ifndef __OVERRIDE__HH_
#define __OVERRIDE__HH_
class base
{
public:
virtual int getValue()
{
return 10;
}
};
class derived :public base
{
public:
int getValue() override
{
return 200;
}
};
#endif
编译运行:输出200,达到我们的预期
总结上述代码原因:
通过使用override
关键字,编译器会在编译时检查Derived
类中的函数是否真正覆盖基类中的虚函数。如果函数签名不匹配,编译器就会发出错误提示。这种检查能够提供一致性和准确性,帮助开发人员避免潜在的错误。
override关键字:
作用:
-
明确标识函数重写:通过在派生类中的函数声明末尾添加
override
关键字,可以显式地表明该函数是对基类中的虚函数的重写。这样可以提高代码的可读性和可维护性。 -
编译器检查:使用
override
关键字可以告知编译器要检查派生类中的函数是否真正重写了基类中的虚函数。如果派生类中的函数没有正确地重写基类中的虚函数(例如函数名、参数列表或返回类型不匹配),编译器将发出错误或警告。
示例:
class base {
public:
virtual void foo();
};
class derived : public base {
public:
void foo() override; // 使用override关键字标识对基类的虚函数foo的重写
};
在上面的例子中,derived
类通过使用override
关键字标识foo()
函数,明确表明该函数是对基类中的虚函数foo()
的重写。
需要注意的是,使用override
关键字只能应用于派生类中重写基类虚函数的情况,而不能用于非虚函数、静态函数或非成员函数。
总结:override
关键字在C++中用于明确表示派生类中的成员函数是对基类中虚函数的重写,并通过编译器的检查来确保准确性。它提高了代码的可读性和可维护性,并帮助开发人员更好地理解继承关系和函数重写的语义。