override在C++中它是覆盖了一个方法并且对其重写,从而达到不同的作用。在我们C++编程过程中,最熟悉的就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。还有一个典型应用就是在继承中也可能会在子类覆盖父类的方法。

1.公有继承

包含两部分:一是“接口”(interface),二是 “实现” (implementation)。

class Shape {
public:virtual void Draw() const = 0;    // 1) 纯虚函数virtual void Error(const string& msg);  // 2) 普通虚函数int ObjectID() const;  // 3) 非虚函数
};class Rectangle: public Shape { ... };
class Ellipse: public Shape { ... };

1. 1 纯虚函数

纯虚函数,继承的是基类成员函数的接口,必须在派生类中重写该函数的实现:

Shape *ps1 = new Rectangle;
ps1->Draw(); // calls Rectangle::DrawShape *ps2 = new Ellipse;
ps2->Draw(); // calls Ellipse::Draw

调用基类的 Draw(),须加 类作用域操作符 ::

ps1->Shape::Draw(); // calls Shape::draw

1.2 普通虚函数

普通虚函数,对应在基类中定义一个缺省的实现 (default implementation),表示继承的是基类成员函数的接口和缺省的实现,由派生类自行选择是否重写该函数。

实际上,允许普通虚函数同时继承接口和缺省实现是危险的。 如下, CarA 和 CarB 是 Car的两种类型,且二者的运行方式完全相同

class Car{
public: virtual void Run(const Car& destination);
};
class CarA: public Car{ ... };
class CarB: public Car{ ... };

这是典型的面向对象设计,两个类共享一个特性 – Run,则 Run可在基类中实现,并由两个派生类继承。

现增加一个新的飞机型号 CarC,其飞行方式与 CarA,CarB 并不相同,假如不小心忘了在 CarC 中重写新的 Fly 函数

class CarC: public Car{ ... // no fly function is declared
};

这就是前面所说的,普通虚函数同时继承接口和缺省实现是危险的,最好是基类中实现缺省行为 (behavior),但只有在派生类要求时才提供该缺省行为.

1. 方法一:

一种方法是纯虚函数 + 缺省实现,因为是纯虚函数,所以只有接口被继承,其缺省的实现不会被继承。派生类要想使用该缺省的实现,必须显式的调用:

class Car{
public: virtual void Run(const Run& destination) = 0;
}; void Car::Run(const Airport& destination)
{ // a pure virtual function default code for Run an Car to the given destination
} class CarA: public Car{
public: virtual void Run(const Car& destination) { Car::Run(destination); }

这样在派生类 CarC 中,即使一不小心忘记重写 Run函数,也不会调用 Car的缺省实现

class CarC: public CAr{
public: virtual void Run(const Car& destination);
}; void CarC::Run(const Car& destination)
{ // code for Run a CarC Car to the given destination
}

2. 方法二:

可以看到,上面问题的关键就在于,一不小心在派生类 CarC中忘记重写 Run函数,C++11 中使用关键字 override,可以避免这样的“一不小心”。
非虚函数:

非虚成员函数没有virtual关键字,表示派生类不但继承了接口,而且继承了一个强制实现(mandatory implementation),既然继承了一个强制的实现,则在派生类中,无须重新定义继承自基类的成员函数,如下:

使用指针调用 Name 函数,则都是调用的 Person::Name()

Student s1; // s1 is an object of type Student Person *p= &s1; // get pointer to s1
p->Name(); // call Name() through pointer Student *s= &s1; // get pointer to s1
s->Name(); // call Name() through pointer

如果在派生类中重新定义了继承自基类的成员函数 Name

class Student : public Person{
public: int Name() const; // hides Person::Name
}; p->Name(); // calls Person::Name()
s->Name(); // calls Student::Name()

此时,派生类中重新定义的成员函数会 “隐藏” (hide) 继承自基类的成员函数

这是因为非虚函数是 “静态绑定” 的,p被声明的是 Person* 类型的指针,则通过 p调用的非虚函数都是基类中的,既使 p指向的是派生类。

与“静态绑定”相对的是虚函数的“动态绑定”,即无论 p被声明为 Person* 还是 Student* 类型,其调用的虚函数取决于 p实际指向的对象类型

2 重写 (override)
在程序中加override 关键字,可以避免派生类中忘记重写虚函数的错误

下面以 Base 基类和 Derived 派生类为例,详细阐述之

class Base {
public: virtual void fun1() const; virtual void fun2(int x); virtual void fun3() &; void fun4() const; // is not declared virtual in Base
}; class Derived: public Base {
public: virtual void fun1();  // declared const in Base, but not in Derived. virtual void fun2(unsigned int x); // takes an int in Base, but an unsigned int in Derived virtual void fun3() &&; // is lvalue-qualified in Base, but rvalue-qualified in Derived. void fun4() const;
};

在派生类中,重写 (override) 继承自基类成员函数的实现 (implementation) 时,要满足如下条件:

一虚:基类中,成员函数声明为虚拟的 (virtual)

二容:基类和派生类中,成员函数的返回类型和异常规格 (exception specification) 必须兼容

四同:基类和派生类中,成员函数名、形参类型、常量属性 (constness) 和 引用限定符 (reference qualifier) 必须完全相同

如此多的限制条件,导致了虚函数重写如上述代码,极容易因为一个不小心而出错

C++11 中的 override 关键字,可以显式的在派生类中声明,哪些成员函数需要被重写,如果没被重写,则编译器会报错。

class Derived: public Base {
public: virtual void fun1() override; virtual void fun2(unsigned int x) override; virtual void fun3() && override; virtual void fun4() const override;
};
class Derived: public Base {
public: virtual void fun1() const override; // adding "virtual" is OK, but not necessary virtual void fun2(int x) override; void fun3() & override; void fun4() const override;
};

1) 公有继承

纯虚函数 => 继承的是:接口 (interface)
普通虚函数 => 继承的是:接口 + 缺省实现 (default implementation)
非虚成员函数 =>继承的是:接口 + 强制实现 (mandatory implementation)
2) 不要重新定义一个继承自基类的非虚函数 (never redefine an inherited non-virtual function
3)在声明需要重写的函数后,加关键字 override
这样,即使不小心漏写了虚函数重写的某个苛刻条件,也可以通过编译器的报错,快速改正错误。

在使用中需要注意以下几点:

覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
覆盖的方法的返回值必须和被覆盖的方法的返回一致;
覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

————————————————
版权声明:本文为CSDN博主「渐无书xh」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42905141/article/details/94405090

C++ 纯虚函数 虚函数 override相关推荐

  1. 38.【C++ 虚函数 纯虚函数 虚基类 (最全详解)】

    虚函数.虚基类.纯虚函数 (一).虚函数 1.什么是虚函数: 2.虚函数的格式: 3.关于虚函数的注意事项: 4.虚函数的作用: 5.虚函数访问格式 6.虚函数的各种疑难杂症 [当指针是基类.但虚函数 ...

  2. 虚函数 虚继承 抽象类

    虚函数.纯虚函数.虚基类.抽象类.虚函数继承.虚继承 虚函数:虚函数是C++中用于实现多态(polymorphism)的机制.核心理念就是通过基类访问派生类定义的函数.是C++中多态性的一个重要体现, ...

  3. c++,不能声明为虚函数的函数

    1.顶层函数:多态的运行期行为体现在虚函数上,虚函数通过继承方式来体现出多态作用,顶层 函数不属于成员函数,是不能被继承的. 2.构造函数: (1)构造函数不能被继承,因而不能声明为virtual函数 ...

  4. C# 虚方法(virtual)覆盖(override) - 隐藏(new) - 重载

    C# 虚方法(virtual)覆盖(override) - 隐藏(new) - 重载 using System; using System.Collections.Generic; using Sys ...

  5. C++基础::语法特性::函数重写(override)与协变返回类型(covariant return type)

    函数重写 在进行本文的协变返回类型(covariant return type)的讨论之前,不妨先重新温故C++关于函数重写的语法规则.协变返回类型与函数重写有着千丝万缕的联系. 首先明确函数重载(o ...

  6. item 12: 把重写函数声明为“override”的

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 C++中的面向对象编程总是围绕着类,继承,以及虚函数.这个世界中, ...

  7. [转载] 纯函数和函数柯里化

    参考链接: 用示例编写Java柯里化Currying函数 文章目录 纯函数什么是纯函数纯函数例子非纯函数例子 函数柯里化函数柯里化简单例子参数复用 纯函数 什么是纯函数 如果函数的调用参数相同,则永远 ...

  8. react之纯函数、函数组件

    纯函数 Pure Function 定义:一个函数的返回结果只依赖于它的参数,并且在执行的过程中没有副作用,我们就把该函数称作纯函数. 特点 1. 函数的返回结果只依赖于它的参数. let foo=( ...

  9. react之纯函数、函数组件、类组件、纯组件

    一.纯函数 Pure Function 定义:一个函数的返回结果只依赖于它的参数,并且在执行的过程中没有副作用,我们就把该函数称作纯函数. - 特点: 1.函数的返回结果只依赖与它的参数(同一个输入只 ...

  10. c++ 函数模板_C/C++编程笔记:C++入门知识,深入解析C++函数和函数模板

    本篇要学习的内容和知识结构概览 函数的参数及其传递方式 1. 函数参数传递方式 传值: 传变量值: 将实参内存中的内容拷贝一份给形参, 两者是不同的两块内存 传地址值: 将实参所对应的内存空间的地址值 ...

最新文章

  1. 构建插件式的应用程序框架(六)----通讯机制(ZT)
  2. TCP服务端程序开发
  3. jsp访问WEB-INF下面的资源
  4. OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
  5. 使用OGR创建dxf格式矢量数据
  6. 元计算:《元计算破解生命密码》听课笔记
  7. 轻松与外来客户进行REST通信
  8. 图像质量评价之数据库
  9. 高性能计算机的基准测试程序包括,QX∕T 148-2020 气象领域高性能计算机系统测试与评估规范(可复制版)(40页)-原创力文档...
  10. Quartz cron 表达式格式
  11. NLP自然语言处理必修清单(修炼法则)
  12. linux gcc编译模式,在Linux中GCC详细模式输出说明
  13. 只需三分钟小白也能学会!新手做自媒体,音乐拼接一晚200多
  14. 下载Google Earth的地图并用ArcMap对其georeferencing
  15. Java多线程-马士兵高并发视频教程笔记
  16. sdr 软件_购买软件定义无线电(SDR)还是传统无线电台?|追求欲望无止境
  17. 描述内存分配方式以及它们的区别?
  18. 浅谈:电商系统常见的几种模式
  19. 网络出口区流量清洗经典引流方案分享
  20. Latex公式内行间距,字体大小控制

热门文章

  1. jQuery使table表格隔行显示不同颜色
  2. CORBA版HelloWorld
  3. C++primer 13.1.2节练习
  4. Java Map 接口
  5. Infopath 2013 通过UserProfileService读取AD用户信息
  6. 【译】Simple MySQL ORM for C
  7. CLR via C# 读书笔记 3-6 比较APM和EAP(异步编程模型和基于事件的编程模式)
  8. 蓝牙激光雕刻机android,一种基于蓝牙微型激光雕刻机及其操作方法专利_专利查询 - 天眼查...
  9. python中循环结构break_Python编程10:跳出循环结构之break和continue
  10. java 9 api_Java9 Process API