首页 > 其他分享 >override和final那些事

override和final那些事

时间:2024-03-23 15:58:53浏览次数:32  
标签:函数 int 子类 那些 override 重写 final

1. override和final简单概括

override和final是C++11中的新特性,这两个新特性可以让我们在继承和重写虚函数时更加安全。

2. override代码实例

我们总会遇到这种情况:在子类中,本来想重写虚函数,结果虚函数却没有被正确地调用。
或者更惨的是,你有时不得不去修改父类虚函数的声明。在所有的子类中查找重载的函数这件事可真的是很麻烦。那么看代码:

#include <iostream>
using namespace std;

struct Base
{
	virtual void doSomething(int i) const
	{
		cout << "This is from Base with " << i << endl;
	}
};

struct Derivied : Base
{
	virtual void doSomething(int i)
	{
		cout << "This is from Derived with " << i << endl;
	}
};

void letDoSomething(Base& base)
{
	base.doSomething(419);
}

int main()
{
	Derivied d;
	letDoSomething(d);  //输出结果: "This is from Base with 419"
	return 0;
}

通过观察这个例子我们发现,子类并没有重写父类的虚函数,Derived::doSomething函数把Base::doSomething的const给搞丢了。所以他们两者并没有相同的函数签名,前者也没有如我们预想的对后者进行重写。确实会有编译器弹出warning提示这个问题,但是往往在我们本意就不想重写虚函数时它也会报警——久而久之我们就麻木了,编译器并不能从根本上解决这个问题。像这样的场景,我们也没有工具来区分告诉编译器我们的本意是否想重写这个父类的虚函数。因此,在C++11中,我们引入了override这个关键字。

代码如下:

  • 如果我们需要重写父类的虚函数,那么在最后加上override,编译器会帮我们判断是否真正重写了虚函数
 struct Derived : public Base 
 {
   // ERROR,编译器报警没有正确重写虚函数,应该是 void doSomething(int i) const override {}
   void doSomething(int i) override 
   {  
     std::cout << "This is from Derived with " << i << std::endl;
   }
 };
  • 下面是正确重写虚函数代码:
#include <iostream>
using namespace std;

struct Base
{
	virtual void doSomething(int i)  const
	{
		cout << "This is from Base with " << i << endl;
	}
};
struct Derivied : Base
{
	void doSomething(int i) const override
	{
		cout << "This is from Derived with " << i << endl;
	}
};

void letDoSomething(Base& base)
{
	base.doSomething(419);
}

int main()
{
	Derivied d;
	letDoSomething(d);  //输出结果: "This is from Base with 419"
	return 0;
}

很简单,加个关键字,就可以让编译器来检查我们又没有正确重写父类的虚函数。因此,任何子类重写虚函数后导致函数签名的变化,都会导致编译器报错。

除此之外,如果你一直使用override,他还会给你带来一个意想不到的收获:在C++11之前,关于子类重写父类虚函数后,子类的虚函数还要不要加virtual关键字,还是个值得争论的问题。人们一开始之所以想在子类的重写函数上也加上virtual,就是为了提醒读代码的人这是个重写的虚函数。但是在有了override之后,这个关键字本身就起了这个作用,之前的做法也就不是必须的了。所以建议的做法是,在最顶层的虚函数上加上virtual关键字后,其余的子类重写后就不再加virtual了,但是要统一加上override。

3. 防止重写

针对上面特性的反面,C++11也讨论了如何防止子类再覆写父类的虚函数了——即父类的某些特性或方法被设计成不想再被改变。在C++11出现前,比较难受的一点就在于,即使父类的虚函数是private的情况下,我们仍然无法阻止它的子类覆写这个方法。

#include <iostream>
using namespace std;

class Base
{
public:
    void doSomething() const
    {
        cout << "I did something" << dontChangeMe() << endl;
    }
private:
    virtual int dontChangeMe() const = 0;
};

class ChildOfBase : public Base
{
private:
    int dontChangeMe() const override 
    { 
        return 419;
    }
};

class BadChildOfChild : public ChildOfBase
{
    int dontChangeMe() const override
    {
        return 61;
    }
};

int main() 
{
    BadChildOfChild badLittleChild;
    badLittleChild.doSomething(); //结果是61
}

在C++11之前,你还对上边的行为无可奈何,至少你无法在语法层面去禁止开发人员这么做。现在,我们有了final关键字来帮我们这个忙。

class ChildOfBase : public Base
{
private:
    int dontChangeMe() const final 
    { 
        return 419;
    }
};

class BadChildOfChild : public ChildOfBase
{
    int dontChangeMe() const override//报错:无法重写final函数
    {
        return 61;
    }
};

关于final和override关键字位置的一个小提示:
1、这两者应放在const,volatile等其他关键字后边,但是应该在纯虚标记,也就是"=0"的前边。
2、一个final的纯虚函数是没什么意义的,因为本身就是一个抽象函数又不让后边的子类覆写给与它实际意义,这就很无聊。
3、另外就是override final和final override并没有什么区别,只是后者读起来可能更顺一些吧。只写一个final并不会像override那样检查覆写类型,所以最好还是两个都写上。
4、在ChildOfBase类的dontChangeMe函数后面加上final后,再去重写ChildOfBase类的dontChangeMe函数就不可能了,但是写一个新的子类继承Base,再重写dontChangeMe还是允许的。

4. final修饰类

final还有第二种用法,直接用在类上,紧跟着类名,表示这个类禁止任何其他类继承它,无论是public继承还是private继承。

class Base final
{
	......
};

class ChildOfBase : public Base//报错:不能将final类作为基类
{
	......
};

但是在给类使用final之前,还是要想清楚final是否真的是必要的,如果不是,那它就是一个****。

总结

override 和 final 都能帮助我们改善虚函数相关的安全性;
而使用final需要更多的权衡,但是override就放心大胆地用吧。

标签:函数,int,子类,那些,override,重写,final
From: https://blog.csdn.net/weixin_45883112/article/details/136967854

相关文章

  • Requests请求方式有那些吗?这篇就够了
    Requests请求方式有那些吗?这篇就够了使用Python的requests库,您可以进行多种类型的HTTP请求.以下是一些常见的请求方式:GET请求:response = requests.get(url)POST请求:response = requests.post(url, data=data)PUT请求:response = requests.put(url......
  • JAVA中HTTPS那些事儿
    转载自:https://www.jianshu.com/p/20180ca83012本章是HTTPS那些事儿的第二篇文章,其他相关文章请参见:前言本篇主要描述JAVA中与HTTPS相关的概念与代码实现。JAVA中的证书KeyStore和TrustStoreSSL层证书校验过程HttpsURLConnection*注意本文纯手工打造,转载请注明出处。J......
  • python 异常捕获、断言(assert 、finally) 与日志(loguru.logger)
    异常捕获常见的异常类型代码执行顺序从上到下依次运行的,如果出错了,后面的代码不会出错。--所以要对异常做处理。常见的异常的类型,不需要记;平时写代码的时候经常会报错,积累常见错误,排查问题。常见异常的报错的类型:NameError,IndexError,KeyError,ValueError,ZeroDivisionE......
  • 240_@Override报错解决
    错误提示:@Overrideisnotallowedwhenimplementinginterfacemethod解决:修改模块编译检查时最低要求的JDK版本为JDK8......
  • 单目测距那些事儿(上) | 从MobileEye谈起
    单目测距那些事儿(上)|从MobileEye谈起全面专业的自动驾驶学习资料:链接前言在ADAS领域,有个功能叫自适应巡航控制(AdaptiveCruiseControl,ACC)。ACC是一种纵向距离控制,具体包括发现目标车辆、判断目标车辆所在路径、测量相对本车的距离和速度,然后进行相应的刹车等制动......
  • 那些放弃Jira的企业都找了哪些替代工具?盘点15款
    15个类似Jira的免费软件:1.PingCode:项目管理系统国产化方面的Jira替代方案;2.Worktile:非研发项目管理的Jira替代方案;3.Redmine:项目管理与问题跟踪的Jira替代方案;4.禅道:敏捷开发和项目管理的Jira替代方案;5.Trello:任务管理和协作的Jira替代方案;6.Visure:需求管理方面的Jira替......
  • Python中那些简单又好用的特性和用法
    Python中那些简单又好用的特性和用法Python作为我的主力语言帮助我开发了许多DevOps运维自动化系统,这篇文章总结几个我在编写Python代码过程中用到的几个简单又好用的特性和用法,这些特性和用法可以帮助我们更高效地编写Python代码1.链式比较x=5y=10z=15ifx<y<z......
  • app分发步骤有那些?
    APP分发的步骤主要包括以下几个方面:准备应用程序:首先,开发人员需要确保应用程序已经经过完整的测试和质量保证,包括功能测试、用户体验测试、性能测试等,以确保其稳定性和可靠性。注册开发者账号:在相应的应用分发平台(如苹果的AppStore、谷歌的GooglePlay等)注册开发者账号,并进行......
  • final
    要么在定义成员变量的时候赋值,要么在构造方法处赋值  ......
  • Python实战:Python异常处理机制及try-except-finally
    本文将详细介绍Python中的异常处理机制,以及如何使用try-except-finally语句来处理程序中的错误和异常情况。我们将深入探讨异常的概念、类型和层次结构,并展示如何在实际编程中应用异常处理来提高代码的健壮性和可维护性。1.引言在编程过程中,错误和异常是不可避免的。异常......