大话C++:第8篇 函数重载

devtools/2024/11/8 22:54:35/

1 函数重载概念

函数重载(Function Overloading)是C++中的一个重要概念,它允许在同一作用域内声明多个同名函数,但这些函数的参数列表(即参数的个数、类型或顺序)必须不同。这样,编译器就能根据调用函数时提供的参数类型和数量来确定应该调用哪个函数。

函数重载的基本规则包括:

  • 参数的数量不同:可以有一个函数接受两个参数,另一个函数接受三个参数。

  • 参数的类型不同:可以有一个函数接受int类型参数,另一个函数接受double类型参数。

  • 参数的顺序不同:如果参数类型相同但顺序不同,也可以构成重载。

注意,函数参数相同指的是函数所有参数类型不完全相同,并且顺序不同,可以构成重载。

2 函数重载语法格式

函数重载的基本语法格式

// 函数重载示例// 第一个函数版本
return_type function_name(parameter_list_1) 
{// 函数体
}// 第二个函数版本,参数列表与第一个不同
return_type function_name(parameter_list_2) 
{// 函数体
}// 可以有更多的版本,只要参数列表不同
return_type function_name(parameter_list_n) 
{// 函数体
}

其中,

  • return_type 是函数的返回类型,它可以是任何有效的C++数据类型。

  • function_name 是函数的名称,对于所有重载版本来说,这个名字必须是相同的。

  • parameter_list_1, parameter_list_2, ..., parameter_list_n 是函数的参数列表,它们定义了每个重载版本接受的参数类型和数量。每个重载版本的参数列表必须至少在一个方面与其他版本不同,以区分它们。

#include <iostream>  // 重载的加法函数,接受两个整数
int add(int num1, int num2) 
{std::cout << "add(int num1, int num2)" << std::endl;return num2 + num2;
}// 重载的加法函数无效
// 重载函数中参数类型完全一致,单纯调换了参数位置,无法实现函数重载
// int add(int num2, int num1)
// {
//     std::cout << "add(int num2, int num1)" << std::endl;
//     return (num2 + num1);
// }// 重载的加法函数无效
// 函数返回值不能作为函数重载的判断依据
// double add(int num1, int num2)
// {
//     std::cout << "double add(int num1, int num2)" << std::endl;
//     return (num1 + num2);
// }// 重载的加法函数,接受三个整数
int add(int num1, int num2, int num3)
{std::cout << "add(int num1, int num2, int num3)" << std::endl;return (num1 + num2 + num3);
}// 重载的加法函数,接受两个浮点数
double add(double num1, double num2) 
{std::cout << "add(double num1, double num2)" << std::endl;return num1 + num2;
}// 重载的减法函数,接受一个整数,一个浮点数
double sub(int num1, double num2)
{std::cout << "sub(int num1, double num2)" << std::endl;return (num2 - num1);
}// 重载的减法函数, 接受一个浮点数,一个浮整数
// 满足“参数类型相同但顺序不同”原则
double sub(double num1, int num2)
{std::cout << "sub(double num1, int num2)" << std::endl;return (num1 - num2);
}int main() 
{ // 两整数相加int num1 = 10;int num2 = 20;int r1 = add(num1, num2);std::cout << "r1=" << r1 << std::endl;// 两浮点数相加double num4 = 3.14;double num5 = 4.13;double r2 = add(num4, num5);std::cout << "r2=" << r2 << std::endl;// 三整数相加int num3 = 30;int r3 = add(num1, num2, num3);std::cout << "r3=" << r3 << std::endl;// 浮点数减整数double r4 = sub(num4, num1);std::cout << "r4=" << r4 << std::endl;// 整数减浮点数double r5 = sub(num1, num4);std::cout << "r5=" << r5 << std::endl;return 0;  
}

3 函数重载实现的原理

函数重载的实现原理主要涉及编译器的处理过程。当编译器遇到函数调用时,它会根据函数调用时提供的参数类型和数量来解析并确定调用哪个重载版本。这个过程大致可以分为以下几个步骤:

  • 名称查找:编译器首先在当前作用域中查找与函数调用中使用的函数名相匹配的函数。

  • 参数匹配:对于找到的每个同名函数,编译器会检查它们的参数列表是否与函数调用中提供的参数类型和数量相匹配。这包括参数的个数、类型和顺序。

  • 最佳匹配选择:如果找到多个匹配的函数版本,编译器会选择一个“最佳匹配”的版本。这通常基于参数类型转换的复杂性和其他因素,如常量性、引用绑定等。

  • 函数选择:编译器根据匹配的结果选择最合适的函数版本进行调用。

为了支持函数重载,编译器通常会使用一种称为“名字修饰”(Name Mangling)的技术。名字修饰是一种将函数名与参数类型信息结合在一起的机制,以便为不同的重载版本生成唯一的标识符。这样,即使函数名相同,由于参数类型不同,编译器也能区分它们。例如,以下两个重载函数:

void foo(int);
void foo(double);

译器可能会将这两个函数名修饰为类似这样的内部名称:


_Z3fooi  // 对于 void foo(int)
_Z3food  // 对于 void foo(double)

其中,_Z3foo_Z3food 是编译器生成的修饰后的函数名,id 分别表示 intdouble 类型。通过这种方式,编译器可以区分调用的是哪个版本的 foo 函数。

4 函数重载注意事项

在使用函数重载时,开发者需要注意以下几点:

  • 函数名相同:重载的函数必须具有相同的名称,这样才能通过不同的参数列表来区分它们。

  • 参数列表不同:函数的参数列表必须不同,这可以通过改变参数的数量、类型或顺序来实现。如果两个函数的参数列表完全相同,它们就不能构成重载。

  • 返回值类型:函数的返回值类型可以相同也可以不同,但返回值类型不能作为函数重载的依据。即使两个函数的返回值类型不同,只要参数列表相同,它们也不能构成重载。

  • 引用作为重载条件:引用可以作为函数重载的条件之一。例如,可以有一个函数接受int的引用,另一个函数接受const int的引用。

  • 函数重载与默认参数:当函数有默认参数时,需要注意不要与重载函数产生歧义。例如,如果一个函数有两个参数,其中第二个参数有默认值,那么它实际上可以被视为一个接受一个或两个参数的函数,这可能会与另一个只接受一个参数的函数产生冲突。

  • 注意作用域函数重载必须在同一个作用域内,这通常意味着它们应该在同一个文件或同一个类的内部定义。

  • 编译器错误提示:如果编译器提示“没有与指定类型匹配的重载函数”,通常是因为调用的函数类型与声明的函数类型不匹配。这时需要检查调用的函数参数类型、数量和顺序是否正确。

  • 避免过度重载:虽然函数重载可以提高代码的灵活性和可读性,但过度使用也可能导致代码难以理解和维护。因此,在设计函数重载时要适度,避免创建过多复杂和相似的函数。

  • 注意函数模板与重载:函数模板也可以实现类似函数重载的效果,但它们的机制是不同的。函数模板是在编译时根据实参类型生成具体的函数版本,而函数重载则是通过不同的函数名(实际上是修饰后的函数名)来区分不同的函数版本。


http://www.ppmy.cn/devtools/113734.html

相关文章

【计算机四级网络工程师】操作系统原理第五章——内存管理(中)

目录 一、页式存储管理方案 1.1基本思想 1.2地址转换与快表 1.2.1页表 1.2.2二级页表 1.2.3散列页表(哈希列表) 1.2.4页式存储管理的地址转换 1.2.5快表 二、段式与段页式存储管理方案 2.1段式存储管理 2.1.1基本思想 2.1.2实现 2.2段页式存储管理 2.2.1基本思想 2.2.2实现 三、…

System.out源码解读——err 和 out 一起用导致的顺序异常Bug

前言 笔者在写一个小 Demo 的过程中&#xff0c;发现了一个奇怪的问题。问题如下&#xff1a; // 当 flagtrue 时打印 a1 &#xff1b;当 flagfalse 时打印 a2。 public static void main(String[] args) {boolean flag false;for (int i 0; i < 10; i) {if (flag) {Sys…

python中Web开发框架的使用

Python 的 Web 开发框架种类繁多&#xff0c;常见的有 Django 和 Flask 这两个框架。它们各有优点&#xff0c;适合不同类型的 Web 应用开发需求。下面&#xff0c;我将详细介绍这两大主流框架的使用方法&#xff0c;让你快速上手 Python 的 Web 开发。 1. Django Django 是一…

Java 入门指南:JVM(Java虚拟机)垃圾回收机制 —— 垃圾收集器

文章目录 垃圾回收机制Stop-the-World垃圾收集器垃圾收集器分类Serial 收集器Serial Old 收集器ParNew 收集器Parallel Scavenge 收集器Parallel Old 收集器CMS 收集器CMS 收集器缺点 G1 收集器G1 收集器特点G1 收集器的分代理念G1 收集器运作过程 垃圾回收机制 垃圾回收&…

Games101图形学笔记——着色

Shading Z-buffering&#xff08;深度缓冲&#xff09; Shading&#xff08;着色&#xff09;画家算法Z-BufferShading(着色&#xff09;Blinn-Phong Reflectance Model&#xff08;布林冯反射模型&#xff09;漫反射能量守恒 着色高光Blinn-Phong Reflection ModelShadingFreq…

工作笔记之CentOS7 重启 RocketMQ

在 CentOS 7 上&#xff0c;RocketMQ 是一个流行的分布式消息中间件&#xff0c;在大规模消息处理和实时数据传输中有着广泛的应用。本文将详细介绍笔者如何在 CentOS 7 上重启 RocketMQ&#xff0c;包括启动 NameServer 和 Broker 这两个核心组件。 作者&#xff1a;朱元禄&am…

『功能项目』怪物的有限状态机【42】

本章项目成果展示 我们打开上一篇41项目优化 - 框架加载资源的项目&#xff0c; 本章要做的事情是按照框架的思想构建项目并完成怪物的自动巡逻状态&#xff0c;当主角靠近怪物时&#xff0c;怪物会朝向主角释放技能 首先新建脚本&#xff1a;BossCtrl.cs (通常把xxxCtrl.cs脚…

【深度学习】【图像分类】【OnnxRuntime】【Python】VggNet模型部署

【深度学习】【图像分类】【OnnxRuntime】【Python】VggNet模型部署 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】【图像分类】【OnnxRuntime】【Python】VggNet模型部署前言Windows平台搭建依赖环境模型转换--pytorch转onnxONN…