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

news2024/11/18 17:51:29

 我是荔园微风,作为一名在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深度学习时代、智能机器时代,我不知道未来还会有什么时代,只记得这一路走来,充满着艰辛与收获,愿同大家一起走下去,充满希望的走下去。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/699963.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【刷题笔记——链表专栏】牛客网:合并两个排序链表

【刷题笔记——链表专栏】牛客网&#xff1a;合并两个排序链表 一、题目描述 二、思路分析 1、创建新的头节点newHead&#xff08;注意这一步&#xff09; 2、循环遍历pHead1和pHead2并进行链表并进行合并&#xff0c;直到pHead1和pHead2其中有一个为null时结束循环 3、合并完…

Win10,Win11玩游戏找不到d3dx9怎么解决

相信有些朋友遇到了d3dx9_42.dll丢失的情况不知道怎么解决&#xff0c;而今日小编带来的这篇文章就是讲解关于d3dx9_42.dll丢失进行修复的操作内容&#xff0c;d3dx9_42.dll丢失怎么解决&#xff1f;&#xff08;修复方法&#xff09;d3dx9 42.dll文件是DirectX中必备文件,许多…

【期末不挂科 学习数据结构】

期末不挂科 学习数据结构 第一章绪论1.1数据结构的基本概念1.1.1基本概念和术语1.数据2.数据元素3.数据对象4.数据类型5.数据结构 1.1.2数据结构三要素1.数据的逻辑结构2.数据的存储结构3.数据的运算 第一章绪论 1.1数据结构的基本概念 1.1.1基本概念和术语 1.数据 数据是信…

Redis7【⑧ Redis集群(cluster)】

Redis集群 Redis 集群是 Redis 数据库的分布式解决方案&#xff0c;它可以将数据分散存储在多个节点上&#xff0c;以支持大规模数据存储和高并发访问。 Redis 集群使用的是基于槽的分区策略&#xff0c;即将数据分成固定数量的槽&#xff0c;每个槽由一个主节点和多个从节点组…

Python基础教程: 入门简介

Python 最初由 Guido van Rossum 在 1991 年开发&#xff0c;当时他在执行其他项目的时候需要编写一个简单的解释器。Python 最初只是一种简单的脚本语言&#xff0c;但在后来的发展中&#xff0c;它迅速成为一种流行的编程语言。 Python 不仅在大型科技企业中应用广泛&#x…

spring cloud 之 gateway

网关介绍 在微服务架构体系中&#xff0c;一个系统会被拆分为很多个微服务&#xff0c;那么作为客户端要如何去调用这么多的微服务呢&#xff1f;如果没有网关的存在&#xff0c;我们只能在客户端记录每个微服务的地址&#xff0c;然后分别调用&#xff0c;当然这样是不现实的…

Mysql事务原理

一、概述 事务&#xff1a;一组操作要么全部成功&#xff0c;要么全部失败&#xff0c;目的是为了保证数据最终的一致性。 数据库一般都会并发执行多个事务&#xff0c;多个事务可能会并发的对相同的一批数据进行增删改查操作&#xff0c;可能就会导致我们说的脏写、脏读、不可…

水站桶装水订水系统桶装水小程序,改变了桶装水行业传统的送水模式;

水站桶装水订水系统桶装水小程序&#xff0c;改变了桶装水行业传统的送水模式&#xff0c;客户通过线上下单&#xff0c;送水工实时接单配送&#xff0c;空桶更好的记录管理&#xff0c;财务数据在后台清晰明了&#xff0c;提高了水站的工作效率。 除此之外&#xff0c;还有很多…

网络系统集成实验(五)| 系统集成路由器OSPF动态、综合路由配置

一、前言 该系列文章将会对网络系统集成课程中相关实验进行更新&#xff0c;本篇为第五篇&#xff0c;有关路由器的OSPF、综合路由配置&#xff0c;包括了OSPF的配置实验、单臂路由实验、RIP配置实验、综合实验等。 注意&#xff1a;该实验的后半部分综合实验基于前面的实验&am…

java Collection集合使用笔记

1、Collection集合概述 它是单例集合的最顶层接口&#xff0c;它表示一组对象&#xff0c;这些对象也称之为Collection的元素JDK不提供此接口任何直接实现&#xff0c;但提供更具体的子接口&#xff08;如&#xff1a;List和Set&#xff09;实现创建Collection集合对象的方法&…

麒麟信安与飞腾携手共赴云端

当前各行业已进入全面云化时代&#xff0c;云桌面技术作为典型办公终端替代方案&#xff0c;凭借其数据安全、便捷运维、综合成本占优的优势正逐步在各行业应用实施。伴随十四五规划加速数字化转型及信息产业核心技术自主化发展&#xff0c;各政企组织迫切需要基于国产软硬件实…

gmap构建离线地图,用createCustomerTiledLayer方法,瓦片地址尾部多了 ?x={x}y={y}z{z} 导致无法显示地图。

gmap构建离线地图&#xff0c;用createCustomerTiledLayer方法&#xff0c;瓦片地址尾部多了 ?x{x}&y{y}&z&{z} 导致无法显示地图。 function initMap() {this.map new GL.Map(map, {center: "120.650847,31.3092434",zoom: 12,zoomControl: false,sca…

青大数据结构【2018】【算法设计】

关键词&#xff1a; 单链表递增、树的先序遍历 1&#xff09;带头结点的单链表L&#xff0c;从首结点开始&#xff0c;依次两两比较&#xff0c;如果前者大于等于后者&#xff0c;说明是非递增的&#xff1b;否则递增。 2&#xff09; 1&#xff09;先遍历二叉树&#xff0c;…

【mars3d】基于vue3的marsgis通用UI库 mars-ui 的使用

一名脑残程序员的mars-ui心酸使用记录。 通过mars3d的官网我们可以看到&#xff0c;有配套的UI库使用&#xff0c;那么我们如何使用到自己的项目中呢&#xff0c;跟着文章一步一步来吧&#xff01; 1、引入UI库 ① 安装ant-design-vue cnpm install ant-design-vue --save②…

如何实现功能插件化

本文将介绍两种方式来实现功能插件化&#xff1a; Java SPISpring factories 在整个插件化的方案中&#xff0c;会涉及到如下 3 个组成部分&#xff1a; 插件定义&#xff08;即将插件定义为一个接口&#xff09; 插件实现&#xff08;即对插件接口的实现&#xff09; 这里…

【需求实现】输入多少就输出多少的拟合任务如何实现(二):进度条简化

文章目录 导读普通的输出方式上下求索TensorBoard是个不错的切入点与Callback参数对应的Callback方法官方的内置Callback官方进度条简单的猜测与简单的验证拼图凑齐了&#xff01; 导读 在训练模型的过程中往往会有日志一堆一堆的困扰。我并不想知道&#xff0c;因为最后我会在…

今天给大家分享几款好用的卸载神器

在日常使用电脑的过程中&#xff0c;我们经常需要安装和卸载各种软件。然而&#xff0c;有时候使用操作系统自带的卸载程序可能无法完全清除程序及其相关文件和注册表项&#xff0c;导致系统出现垃圾文件和残留问题。为了解决这个困扰&#xff0c;今天我将向大家分享几款好用的…

【Spring】基于注解方式存取JavaBean:Spring有几种注入方式?有什么区别?

前言 Hello&#xff0c;我是小黄。众所周知&#xff0c;Spring是一个开源的Java应用程序框架&#xff0c;其中包括许多通过注解实现依赖注入的功能。Spring提供了多种注入方式&#xff0c;可以满足不同的需求和场景。常见的注入方式包括构造函数注入、Setter方法注入和属性注入…

【Redis】Redis的高可用与持久化

文章目录 一、Redis 高可用1. 概念2. 高可用技术以及作用2.1 持久化2.2 主从复制2.3 哨兵2.4 集群 二、Redis 持久化1. 持久化的功能2. Redis 持久化方式 三、RDB 持久化1. 概述2. 触发条件2.1 手动触发2.2 自动触发2.3 其他自动发机制 3. 执行流程4. 启动时加载 四、AOF 持久化…

Modin 入门学习

Modin 是一个 Python 第三方库&#xff0c;用于加速 Pandas 的 API 执行速度。原始的 Pandas 是单线程执行的&#xff0c;而 Modin 则重新打包了 Pandas 里面的 API&#xff0c;使其同时在多个内核中运行&#xff0c;提高硬件性能的利用率。 使用方法很简单&#xff0c;安装 M…