IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C和C++的区别(4) C++支持函数重载 -> 正文阅读

[C++知识库]C和C++的区别(4) C++支持函数重载


一、什么是函数重载

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些函数的形参列表(参数个数类型或者类型顺序),常用于 实现 功能类似而数据类型不同的情况。
注意:函数重载与返回值无关,也就是函数返回值的类型不同,其它相同并不构成函数重载。还有就是C语言中没有函数重载。

例如希望计算两个变量的和,这两个变量可能有多种类型,可能是 int、float、char、long 、double等:

#include<iostream>
using namespace std;

int Add(int x, int y) {//函数1
	return x + y;
}

double Add(double x, double y) {//函数2  相对函数1 参数类型不同
	return x + y;
}

double Add(double x, double y, double z) {//函数3  相对函数2 参数个数不同
	return x + y + z;
}

int Add(int x, char y) {//函数4
	return x + y;
}

int Add(char y, int x) {//函数5  相对函数4 类型顺序不同
	return x + y;
}

int main() {
	int a = 1;
	int b = 2;
	int c = Add(a, b);

	double x = 3.1;
	double y = 4.2;
	double z = Add(x, y);

	cout << c << endl;
	cout << z << endl;

	return 0;
}

上面两个函数,函数1和函数2构成函数重载。在函数调用时,编译器会自动根据函数参数类型的不同调用与之匹配的函数。

注意:当函数中用到缺省参数而参数类型没有改变就不属于函数重载,如:

int Add(int a, int b)
{
	return a + b;
}

int Add(int a, int b = 10)
{
	return a + b;
}

注意:只有返回类型不同也不属于函数重载,如:

int Add(int a, int b)
{
	return a + b;
}

short Add(int a, int b)
{
	return a + b;
}

注意:同类型参数只调换参数名顺序也不属于函数重载,如:

int Add(int a, int b)
{
	return a + b;
}

int Add(int b, int a)
{
	return a + b;
}

二、C++如何实现函数重载

在C/C++中,程序生成可执行程序需要经过4个阶段 预处理、编译、汇编、链接。如下图所示:
在这里插入图片描述

在日常应用中项目通常是由多个头文件和多个源文件构成,如果当前a.cpp中调用了b.cpp中定义的Add函数时,.o文件链接前,a.o的目标文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。

链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就会到b.o的符号表中找Add的地址,然后链接到一起。

在链接时,面对Add函数链接器会使用哪个名字,每个编译器都有自己的函数名修饰规则。

下面是C语言Add函数的符号表中的命名,在c语言中,函数的符号表命名是直接用函数名直接修饰的(编译环境:VS2019):
(特意制造了一个未定义错误)
在这里插入图片描述
在c++中,windows下函数的命名规则不是直接用函数名直接命名的,并且发现两个Add函数的命名不同(编译环境:VS2019):
在这里插入图片描述
总体格式为:

?+[构造/析构]+函数名+@@+调用约定+返回值类型+各个参数类型+结束标志

调用约定
__cdecl:@@YA

返回值、参数的类型标识
H:int
N:double

结束标志
参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“Z”标识结束。

有兴趣可以参考该文:VS编译器C/C++函数编译后的名字修饰

当在linux下,采用g++编译器编译后的函数修饰与vs2019不同。

int Add(int x,int y)会被命名为_Z3Addii

float Add(float x,float y)会被命名为_Z3Addff

其命名规则是【_Z+函数名长度+函数名+类型首字母】
在这里插入图片描述

结论:从上面的实例看出,C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,也就支持了重载。也再次印证了函数重载要求参数不同(参数个数类型或者类型顺序),而跟返回值没关系。通过实例我们可以从本质上理解函数重载。


三、C语言为何不支持函数重载

在C语言中,函数的符号表命名是直接用函数名直接修饰的(编译环境:VS2019):
(特意制造了一个未定义错误)
在这里插入图片描述
在同一作用域中如果声明同名函数,则编译后函数符号表存在多个同名的符号将无法确定链接到哪个的情况,这将导致编译失败。


四、extern “C”

在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,表示该函数按照C语言规则来编译。当C需要调用C++函数时,该C++函数也必须声明为extern “C”。

extern "C" int Add(int a, int b);

此时Add将不能重载。

C++中,同一作用域不能出现两个以C风格编译的同名函数,如下:
在这里插入图片描述
C++中,同一作用域出现一个以C风格编译的函数与不以C风格编译的函数同名,程序编译不会报错,如下:
在这里插入图片描述


总结

C语言没办法支持重载,因为编译后同名函数没办法区分来链接。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 10:25:04  更:2022-08-06 10:25:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:07:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码