C++ 中函数重载、覆盖与隐藏详解

发布时间 - 2026-01-11 01:02:27    点击率:

C++ 中函数重载、覆盖与隐藏详解

在C++语言中,函数扮演着很重要的角色,不管面向过程设计,还是基于对象设计;不管是面向对象编程,还是基于泛型编程,函数都可以随处而见。在谈论C++中的函数重载、覆盖和隐藏之前,先回顾下函数的基础知识。

成员函数的重载、覆盖与隐藏

成员函数的重载、覆盖(override)与隐藏很容易混淆,C++程序员必须要搞清楚
概念,否则错误将防不胜防。

8.2.1 重载与覆盖

成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。

覆盖是指派生类函数覆盖基类函数,特征是:

(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。

示例8-2-1 中,函数Base::f(int)与Base::f(float)相互重载,而Base::g(void)

被Derived::g(void)覆盖。

#include <iostream>
using namespace std;
class Base
{
public:
void f(int x){ cout << "Base::f(int) " << x << endl; }
void f(float x){ cout << "Base::f(float) " << x << endl; }
virtual void g(void){ cout << "Base::g(void)" << endl;}
};
class Derived : public Base
{
public:
virtual void g(void){ cout << "Derived::g(void)" << endl;}
};
void main(void)
{
Derived d;
Base *pb = &d;
pb->f(42); // Base::f(int) 42

pb->f(3.14f); // Base::f(float) 3.14
pb->g(); // Derived::g(void)
}

示例8-2-1 成员函数的重载和覆盖

8.2.2 令人迷惑的隐藏规则

本来仅仅区别重载与覆盖并不算困难,但是C++的隐藏规则使问题复杂性陡然增加。

这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual
关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual
关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

示例程序8-2-2(a)中:

(1)函数Derived::f(float)覆盖了Base::f(float)。
(2)函数Derived::g(int)隐藏了Base::g(float),而不是重载。
(3)函数Derived::h(float)隐藏了Base::h(float),而不是覆盖。

#include <iostream>
using namespace std;
class Base
{
public:
virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
void g(float x){ cout << "Base::g(float) " << x << endl; }
void h(float x){ cout << "Base::h(float) " << x << endl; }
};
class Derived : public Base
{
public:
virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
void g(int x){ cout << "Derived::g(int) " << x << endl; }
void h(float x){ cout << "Derived::h(float) " << x << endl; }
};

示例8-2-2(a)成员函数的重载、覆盖和隐藏
据作者考察,很多C++程序员没有意识到有“隐藏”这回事。由于认识不够深刻,
“隐藏”的发生可谓神出鬼没,常常产生令人迷惑的结果。
示例8-2-2(b)中,bp 和dp 指向同一地址,按理说运行结果应该是相同的,可事
实并非这样。

void main(void)
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
// Good : behavior depends solely on type of the object
pb->f(3.14f); // Derived::f(float) 3.14
pd->f(3.14f); // Derived::f(float) 3.14
// Bad : behavior depends on type of the pointer
pb->g(3.14f); // Base::g(float) 3.14
pd->g(3.14f); // Derived::g(int) 3 (surprise!)
// Bad : behavior depends on type of the pointer
pb->h(3.14f); // Base::h(float) 3.14 (surprise!)
pd->h(3.14f); // Derived::h(float) 3.14
}

示例8-2-2(b) 重载、覆盖和隐藏的比较

8.2.3 摆脱隐藏

隐藏规则引起了不少麻烦。示例8-2-3 程序中,语句pd->f(10)的本意是想调用函
数Base::f(int),但是Base::f(int)不幸被Derived::f(char *)隐藏了。由于数字10
不能被隐式地转化为字符串,所以在编译时出错。

class Base
{
public:
void f(int x);
};
class Derived : public Base
{
public:
void f(char *str);
};
void Test(void)
{
Derived *pd = new Derived;
pd->f(10); // error
}

下面是补充大家可以参考一下

函数的声明包括函数的返回值类型,函数名称,参数列表(参数的类型、参数的个数、参数的顺序)。例如,声明一个两个整数之和的函数,int iAdd(int iNum1,int iNum2);而函数的定义可以理解为对函数功能的详尽而准确的解说,通俗点,就是实现函数“how to do?”的效能。两个整数之和函数的定义如下:

int iAdd(int iNum1,int iNum2)
{
   return (iNum1+iNum2);
}

       仔细观察函数的声明和定义,我们不难发现,函数的定义就是除掉函数声明后面的分号,换之成大括号,在大括号里面实现函数的功能。虽然在某些情况下,可以容许不对函数进行声明,只需要对函数定义,就能调用函数了。但是,强烈建议养成先声明函数,然后再定义函数,最后在调用函数的良好习惯。关于函数的基础知识,暂时论述到这。

       现在,进入本文的主题。函数重载(function overload),它是在同一可访问区域内部声明具有几个不同参数列(参数的类型、参数的个数,参数的顺序)的相同函数名称的一种机制,函数的调用是根据不同的参数类型和最佳匹配原则确定最终使用那个函数。函数覆盖(function override)是在派生类中完全一致性地声明了父类中的函数,区别在于函数定义中的大括号之间的内容可以不同,并且该函数在父类中有关键字virtual标识;函数隐藏(function hide)是指在派生类中函数与父类函数完全一致,但是在父类中该函数没有关键字virtual标识,或者是指在派生类中函数与父类的函数名相同,参数列表不一样,父类中的该函数可有也可无关键字virtual标识。

函数重载的特征:相同的范围内(在同一个类中),函数的名称相同,参数列表不同,virtual关键字可有可无;函数覆盖的特征:在不同的范围内(父类与派生类),函数的名字相同,参数列表相同,父类函数必须有关键字virtual;函数隐藏的特征:在不同范围内(父类与派生类),函数的名字相同,参数列表相同,但是父类函数没有关键字virtual或者,参数列表不相同,父类函数中virtual关键字可有可无。

为了直观地理解,请看下面的代码。

#include<iostream>
using namespace std;
class A
{
public:
   void print(int iNum)
   {
     cout<<"在类A中,参数类型是整型"<<endl;
   }
   void print(float fNum)
   {
     cout<<"在类A中,参数类型是单精度浮点型"<<endl;
   }
 virtual void print(void)
   {
     cout<<"在类A中,参数类型是空类型"<<endl;
   }
};
class B:public A
{
public:
   void print( void)
   {
     cout<<"在类B中,参数类型是空类型"<<endl;
   }
 
   void print(int iNum)
   {
     cout<<"在类B中,参数类型是整型"<<endl;
   }
 };
int main()
{
   A a;
   B b;
  //函数的重载
   a.print();
   a.print(1);
   a.print(1.0f);
  //函数的覆盖
   b.print();
 //函数的隐藏
   b.print(1);
  return 0;
}

      运行结果是:

   在类A中,参数类型是空类型
   在类A中,参数类型是整型
   在类A中,参数类型是单精度浮点型
   在类B中,参数类型是空类型
   在类B中,参数类型是整型

     通过上述代码和运行的结果,简明地知道了函数重载,覆盖和隐藏。恰当里利用这些特性,可以编写出更加有效、清晰和精简的代码。                           

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


# C++函数重载  # 覆盖  # 隐藏  # C++  # 中函数重载、覆盖与隐藏实例  # C++基础学习之函数重载的简单介绍  # C++中函数重载实例详解  # 深度探究C++中的函数重载的用法  # 深入解析C++中的函数模板和函数的默认参数  # C++函数模板与类模板实例解析  # C++中函数模板的用法详细解析  # C++程序函数的重载和函数模板示例代码  # 类中  # 是指  # 派生类  # 可有可无  # 整型  # 浮点  # 而不是  # 几个  # 是在  # 就能  # 神出鬼没  # 只需  # 它是  # 很容易  # 也可  # 希望能  # 防不胜防  # 在同一个  # 很重要  # 意识到 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?  百度浏览器如何管理插件 百度浏览器插件管理方法  laravel怎么用DB facade执行原生SQL查询_laravel DB facade原生SQL执行方法  如何在万网开始建站?分步指南解析  Laravel如何实现数据导出到PDF_Laravel使用snappy生成网页快照PDF【方案】  Python文本处理实践_日志清洗解析【指导】  Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】  佛山网站制作系统,佛山企业变更地址网上办理步骤?  php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】  Laravel如何编写单元测试和功能测试?(PHPUnit示例)  Laravel Octane如何提升性能_使用Laravel Octane加速你的应用  ChatGPT 4.0官网入口地址 ChatGPT在线体验官网  浅述节点的创建及常见功能的实现  教学论文网站制作软件有哪些,写论文用什么软件 ?  如何挑选高效建站主机与优质域名?  Laravel如何使用Blade模板引擎?(完整语法和示例)  如何选择PHP开源工具快速搭建网站?  Laravel如何与Inertia.js和Vue/React构建现代单页应用  IOS倒计时设置UIButton标题title的抖动问题  ChatGPT常用指令模板大全 新手快速上手的万能Prompt合集  利用vue写todolist单页应用  如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?  php读取心率传感器数据怎么弄_php获取max30100的心率值【指南】  Laravel如何使用Eloquent ORM进行数据库操作?(CRUD示例)  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  Python3.6正式版新特性预览  中山网站制作网页,中山新生登记系统登记流程?  Laravel怎么上传文件_Laravel图片上传及存储配置  Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能  Python制作简易注册登录系统  宙斯浏览器文件分类查看教程 快速筛选视频文档与图片方法  长沙企业网站制作哪家好,长沙水业集团官方网站?  微信小程序制作网站有哪些,微信小程序需要做网站吗?  HTML 中动态设置元素 name 属性的正确语法详解  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  如何在Windows 2008云服务器安全搭建网站?  Laravel Artisan命令怎么自定义_创建自己的Laravel命令行工具完全指南  Laravel怎么实现微信登录_Laravel Socialite第三方登录集成  Android okhttputils现在进度显示实例代码  Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转  深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?  php结合redis实现高并发下的抢购、秒杀功能的实例  瓜子二手车官方网站在线入口 瓜子二手车网页版官网通道入口  阿里云网站搭建费用解析:服务器价格与建站成本优化指南  实现点击下箭头变上箭头来回切换的两种方法【推荐】  如何在橙子建站中快速调整背景颜色?  Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】  Laravel怎么实现搜索功能_Laravel使用Eloquent实现模糊查询与多条件搜索【实例】  如何用JavaScript实现文本编辑器_光标和选区怎么处理  清除minerd进程的简单方法