Visual C++中函数的覆盖和函数的隐藏

2023-11-18

 我是荔园微风,作为一名在IT界整整25年的老兵,今天来聊聊Visual C++中函数的覆盖和函数的隐藏。

Visual C++中函数的覆盖和函数的隐藏与JAVA有很大不同,有些容易搞错的点和概念,我们要特别注意。

首先,先满足一下急性子的同学,因为有的同学是因为急于了解虚函数和纯虚函数才来看这篇帖子的,那你可以先这样理解:

C++中的虚函数就是JAVA中的普通函数, C++ 中的纯虚函数就是JAVA中的抽象函数, C++ 中的抽象类就是JAVA中的抽象类, C++ 中的虚基类就是JAVA中的接口。

这就是本人的学习方法和别人不一样的地方,我年轻时学C++始终不得要领,于是我把JAVA学会后再去学C++,就全都搞明白了。所以我的帖子都是用这种方法去学C++的。希望那些学C++很吃力的同学可以来借鉴我的这个学习方法。

好了,我们先来看一个程序,一个父亲和一个儿子,希望父亲的学习本领能被儿子继承下去。我们在儿子类中重新定义学习方法。我们希望如果对象是儿子,就调用 儿子类的学习方法,如果对象是父亲,那么就调用父亲类的学习方法。

#include <iostream>
using namespace std;
 
class Father
{
public:
  void eat()
  {
    cout<<"eat"<<endl;
  }
  void run()
  {
    cout<<"run"<<endl;
   }
  virtual void study()
  {
    cout<<"study"<<endl;
  }
};
 
class Son : public Father
{
public:
  void study()
   {
    cout<<"new study"<<endl;
  }
};
 
void fn(Father *p)
{
    p->study();
}
 
int main()
{
  Father *p;
  Son boy;
  p=&boy;
  fn(p);
  return 0;
}

在基类父亲类的study函数前添加了virtual关键字,声明该函数为虚函数。在派生类儿子类中重写了 study函数,我们注意到, 儿子类的study函数和父亲类的study函数完全一样,无论是函数名,还是参数列表都是一样的,这称为函数的覆盖(override)。

我们必须知道构成函数覆盖的条件为:(1)基类函数必须是虚函数(使用 virtual关键字进行声明)。(2)发生覆盖的两个函数要分别位于派生类和基类中。(3)函数名称与参数列表必须完全相同。由于C++的多态性是通过虚函数来实现的,所以函数的覆盖总和多态关联在一起(这一点和JAVA十分相似, 但是JAVA不需要virtual这种关键词)。在函数覆盖的情况下,编译器会在运行时根据对象的实际类型来确定要调用的函数。

我们再看代码:

#include <iostream>
using namespace std;
 
class Father
{
public:
  void eat()
  {
    cout<<"eat"<<endl;
  }
  void run()
  {
    cout<<"run"<<endl;
   }
  void study()
  {
    cout<<"study"<<endl;
  }
};
 
class Son : public Father
{
public:
  void study()
   {
    cout<<"new study"<<endl;
  }
};
 
void fn(Father *p)
{
    p->study();
}
 
int main()
{
  Father *p;
  Son boy;
  p=&boy;
  fn(p);
  return 0;
}

这个其实又回到我之前一个帖子的内容了,大家有兴趣可以看看那个帖子:

Visual C++中的虚函数和纯虚函数的原理

大家应该可以看出来这段代码前面代码的区别。在这段代码中,派生类儿子类中的study函数和基类父亲类中的study函数是完全一样的,不同的是study函数不是虚函数,这种情况称为函数的隐藏。所谓隐藏,是指派生类中具有与基类同名的函数(不考虑参数列表是否相同),从而在派生类中隐藏了基类的同名函数。

初学VC者很容易把函数的隐藏与函数的覆盖、重载相混淆,我们看下面两种函数隐藏的情况:

(1)派生类的函数与基类的函数完全相同(函数名和参数列表都相同),只是基类的函数没有使用virtual关键字。此时基类的函数将被隐藏,而不是被覆盖。

(2)派生类的函数与基类的函数同名,但参数列表不同,在这种情况下,不管基类的函数声明是否有 virtual关键字,基类的函数都将被隐藏。注意这种情况与函数重载的区别,重载发生在同一个类中。

下面我们给出一个例子,以帮助大家加深理解函数的覆盖和隐藏
 

class Father
{
public:
  virtual void fn();
};

class Son:public Father
{
public:
  void fn(int);
};

class Grandson:public Son
{
public:
  void fn();
};

在上面代码中, 儿子类的 fn(int)函数隐藏了父亲类的fn()函数, 儿子类 fn(int)函数不是虚函数(注意和覆盖相区别)。 孙子类的 fn()函数隐藏了 儿子类的 fn(int)函数,由于 孙子类的 fn()函数与 父亲类的fn()函数具有同样的函数名和参数列表,因此 孙子类的 fn()函数是一个虚函数,覆盖了父亲 类的 fn()函数。注意,在孙子类中, 父亲类的 fn()函数是不可见的,但这并不影响 fn 函数的覆盖。

当隐藏发生时,如果在派生类的同名函数中想要调用基类的被隐藏函数,那么可以使用“基类名::函数名(参数)”的语法形式。例如,要在儿子类的fn(int)方法中调用父亲类的fn()方法,可以使用Father::fn()语句。

有的初学者可能会想,怎样才能更好地区分覆盖和隐藏呢?实际上只要记住一点:

函数的覆盖发生在派生类与基类之间,两个函数必须完全相同,并且都是虚函数。那么不属于这种情况的就是隐藏了。

作者简介:荔园微风,1981年生,高级工程师,浙大工学硕士,软件工程项目主管,做过程序员、软件设计师、系统架构师,早期的Windows程序员,Visual Studio忠实用户,C/C++使用者,是一位在计算机界学习、拼搏、奋斗了25年的老将,经历了UNIX时代、桌面WIN32时代、Web应用时代、云计算时代、手机安卓时代、大数据时代、ICT时代、AI深度学习时代、智能机器时代,我不知道未来还会有什么时代,只记得这一路走来,充满着艰辛与收获,愿同大家一起走下去,充满希望的走下去。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Visual C++中函数的覆盖和函数的隐藏 的相关文章

随机推荐

  • 标注一致性:Inter-Annotator Agreement(IAA)

    评价者之间的一致性 Kappas Inter rater agreement Kappas 简书
  • Acwing提高课DP二刷(考研复习)

    前言 本博客主要是为了准备考研数据结构自命题而写的 主要为个人复习使用 里面的题博主在大一大二基本都刷了若干遍 所以这里只写一些简单的思路和总结评语 供日后回顾复习使用 DP 1 acwing1010 导弹拦截 题目大意 利用若干组互相独立
  • vue for循环列表(插槽)输入数据操作

    vue for循环列表 插槽 输入数据操作 1 给循环的每一行的编辑框添加chang事件 输入框 参数 数据的唯一key 绑定的键名 event target value值 下拉框 参数 数据的唯一key 绑定的键名 event值 HTML
  • c++学习之继承

    继承的优点 gt 减少重复代码 class A public B A类称为子类或派生类 B类称为父类或者基类 派生类中的成员 包含两大部分 一类是从基类继承过来的 一类是自己增加的成员 从基类继承过来的表现为共性 而新增的成员表现了个性 代
  • Mysql压力测试(sysbench)

    目录 配置项目环境 参考 采用sysbench压测mysql详解 dream21st的博客 CSDN博客 实验步骤 1 安装sysbench工具 2 在master上创建用户和库 配置用户的权限可以使他可以访问库 Mysql的主从复制 3
  • Java开发工具Idea Revert操作

    Revert是撤销操作 类似于Ctrl Z 不同的是 Revert是以版本为单位 撤销整个版本 可以这样理解Revert操作 假如有V1 V2 V3 V4 V5五个版本 Revert撤销V3版本 实际上就是合并V2版本和V5版本 并对V2版
  • Firefox如何快速关闭网页

    问题You 火狐浏览器如何通过鼠标滑动 快速关闭窗口 火狐浏览器可以通过安装扩展程序来实现通过鼠标滑动快速关闭窗口的功能 以下是具体步骤 打开火狐浏览器 在地址栏中输入 about addons 并回车 在左侧菜单中选择 扩展 然后在右侧搜
  • iOS中.obj、.usdz、.dae和.scn格式之间的转化(思路清晰版)

    作者最近在写项目的过程中遇到了一些3d模型格式问题 故写下这篇文章记录一下解决问题的过程 示例 如果我们想用SceneKit库来实现在默认背景中展示一个3D模型 大致可以这样写代码 var sceneView SCNView var sce
  • 围圈数数淘汰游戏

    在围圈游戏中 规则是从某个数同时开始逆时针和顺时针走一定步长 淘汰对应索引的人员 则有两种情况可能顺逆时针轮到同一个人或许人不同 可以通过一个函数确定每走一步数数的索引值 用一个数组表示每个人是否out 的标志位 初始数组每个值为1 out
  • 编写表格树GridTree过程遇到的问题

    项目中用到不少的树和表格 但是要用到表格树的地方不是很多 但是有时候需要的时候却不好找到 所以就在闲暇的时候自己找了一下 结果发现了很简单的 但是不满足项目的需求 于是就看懂了别人的东西之后 再结合自己的理解 干脆就做一个表格树好了 从写下
  • Angular 6 安装到使用

    TOC 前端 Angular 6 安装到使用 1 下载nodejs 并安装到本地 配置好环境变量 访问nodejs的官方网站的downdolad 网址 https nodejs org en download npm v 查看是否安装成功
  • 强大的jQuery图表插件库Highcharts支持线性图、饼状图、柱状图、区域图、气泡图

    Highcharts是一个纯JavaScript编写的jQuery图表插件库 Highcharts提供了简单的方式为您的网站或项目添加动态图表 Highcharts支持线性图 饼状图 柱状图 区域图 气泡图等近20种图表类型 下载地址 ht
  • mybatis(19)——choose标签,when标签和otherwise标签

    代码
  • JMeter简单使用

    一 下载安装 1 在官网下载或者在 share 192 168 1 201 share 开发工具 java apache jmeter 5 5 zip 2 解压 执行文件在bin目录中 二 常用测试组件 1 线程组 线程组是JMeter 中
  • 服务配置宝塔面板搭建环境及部署项目

    服务配置宝塔面板搭建环境及部署项目 1 登录你所购买阿里云服务器的账号 2 点击控制台 云服务器ecs 3 开通安全组开启端口 把需要访问的端口进行配置 选入方向 如 6379 8080 3306 80 21 22 443 4 获取服务器公
  • FOC和SVPWM的C语言代码实现   

    FOC和SVPWM的C语言代码实现 SVPWM的原理讲解在这儿 https blog csdn net qlexcel article details 74787619 comments 现在开始分析C语言的代码 代码建议复制到notepa
  • 【UE4】DataTable - 数据表

    本文使用 UE 4 26 引擎自带 ARPG 项目 从代码和编辑器两个方面记录一下 UE4 中的 DataTable 也就是数据表的用法 一 DataTable 是什么 DataTable 就是数据表 以下简称 DT 也就是二维的 M 行
  • OLED透明屏轻量化设计:提升便携性与用户体验的新方向

    随着科技的不断进步 OLED透明屏作为一种新兴的显示技术正逐渐走入人们的视野 除了在视觉效果上的优势 OLED透明屏在重量方面的设计也备受关注 对此 尼伽将深入探讨OLED透明屏轻量化设计的重要性 策略以及应用案例 希望看后对您有所启发 一
  • 面试机试题目,使用Spring + SpringMVC +Mybatis + html + css实现员工管理系统

    文章目录 机试挑战 需求分析 简介 访问地址 http 39 99 237 90 8080 employee http 39 99 237 90 8080 employee 源码 https github com Listen Y Java
  • Visual C++中函数的覆盖和函数的隐藏

    我是荔园微风 作为一名在IT界整整25年的老兵 今天来聊聊Visual C 中函数的覆盖和函数的隐藏 Visual C 中函数的覆盖和函数的隐藏与JAVA有很大不同 有些容易搞错的点和概念 我们要特别注意 首先 先满足一下急性子的同学 因为