广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++ 函数重载背后的原理
  • 808
分享到

C++ 函数重载背后的原理

2024-04-02 19:04:59 808人浏览 泡泡鱼
摘要

目录一、函数重载二、函数重载的原理三、为何c++可以支持重载1.程序的编译链接四、C语言为何不支持重载1.C++为何可以支持函数重载五、C++和C语言相互调用1.创建静态库2.C++

一、函数重载

我们可能对函数很是熟悉,但是重载又是什么意思呢?我们先来用一个具体的场景来分享.

一天,张三的老板要你写一个两位数相加的函数,张三心想这不很简单吗?手指一动,结果就出来了,挺简单的嘛.

int add(int x, int y)
{
	return x + y;
}

现在老板看张三的代码立马火了,你是怎么想的,要是我想12,10.9相加呢?你这个就只能两个整型相加,回去修改!!!张三听到老板的话不由得反驳道:这怎么改,总不能再写一个add1,add2…吧.老板听到了张三的嘟囔,生气道,你没有学过函数重载吗?看看下面的代码,回去好好学习学习,基础都不扎实.

张三看到代码,不由大吃一惊,C++还可以这么写?好神奇啊,我要好好看看书.

int add(int x, int y)
{
	return x + y;
}
double add(double x, int y)
{
	return x + y;
}
double add(int x, double y)
{
	return x + y;
}

我们可不希望张三这种事发生在我们身上,先来看看函数重载的定义

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的
形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题 .

可能大家不喜欢看定义,我这里给一个总结.

函数重载要满足下面的要求.

  • 函数名相同
  • 参数的类型,个数,顺序有一个不同就可以了
  • 返回类型不做要求

二、函数重载的原理

一般情况下,我们知道了函数重载到会应用就可以了,但是对于我们来说需要我们看看他们的原理,为什么C语言不支持重载,C++支持重载?这些都是问题.

三、为何C++可以支持重载

我们先用C++的编译器简单的看看如何执行程序,下面是我在linux环境下使用g++来完成的,大家要是不太懂,可以先不管,直接理解C++的原理.

我们先来看看现象,发现C++可以精准的找到需要匹配的函数,这是我们所疑惑的.

// test.h
#pragma once 
#include <iOStream>
#include <stdio.h>
using std::cout;
void func(int a, double b);
void func(double a, int b);
//test.cpp
#include "test.h"
//写两个函数   函数形成重载
void func(int a, double b)
{
	printf("%d %lf", a, b);
}
void func(double a, int b)
{
	printf("%lf %d", a, b);
}
//Mian.cpp

#include "test.h"
int main()
{
	func(10, 2.20);
	return 0;
}

1.程序的编译链接

关于这一点,我们先简单的说说,之前我们详细的谈过.一个文件变成一个可执行程序需要经过下面4个步骤.

  • 预处理 宏替换 头文件展开 注释替换 main.cpp -> main.i test.cpp -> test.i
  • 编译 检查语法 ,代码变换成汇编语言 main.i -> main.s test.i -> test.s
  • 汇编 汇编语言变成二进制语言,各个文件变成目标文件 main.s -> main.o test.s -> test.o
  • 链接 多个目标文件+链接库发生链接

这里我们需要重点谈谈链接,这是我们今天最重要的一部分

链接就仅仅只是目标文件的合并吗?不是的,它要完成的任务很多,其中最重要的就是<font color = red>找到函数的地址,链接对应上,合并到一起</font>

当我们进行过头文件的展开后,Main.cpp中有func函数的声明和调用.在编译和汇编的过程中存在一个符号表,这个符号表记录了函数的定义以及相应的映射.这是很重要的.符号表里面包含了函数名和函数的地址.

每一个目标文件(.o)都包含一个符号表和一系列指令,我们看看入和完成函数链接.

现在到mian.o的指令这里了,前面的一些列指令都正常经行,直到它遇到了func这个点,要是看过C语言的汇编语言的朋友们可能对下面的比较熟悉.

到了func这里,编译器开始call (func: ?),编译器不知道func的地址,但是前面头文件的的展开中func函数已经声明了,所以编译器知道了func是一个函数.就先给它一个无效的地址.当程序进行链接时,编译器一看它是一个无效地址,会拿函数名和其他的.o文件里面的符号表去碰,碰到了就填上,找不到就会报连接错误.

四、C语言为何不支持重载

到这里就可以明白了,当我们拿函数名去碰的时候,符号表里面存在多个相同的函数名,编译器就不会识别该用哪个.更何况存在相同函数名的.c文件有时都不可能编译过.

GCc对函数名都不会做任何处理,这也是C语言不支持函数重载的原因.

1.C++为何可以支持函数重载

到这里我们就可以得到了结果,既然在链接的时候无效的函数会拿函数名去其他的符号表里面去碰,那么只要我们看看重载的函数名像不像同就可以了,大家可能会有些疑惑,重载的函数名不是相同的吗?是的,但是C++编译器会做一定的处理.这里每个编译器都有自己的函数名修饰规则 这就是C++ 支持重载的原理.

这就是C可以支持重载的原因,g的函数修饰后变成【_Z+函数名长度+函数名+类型首字母1+类型首字母2…】,也是我们只对参数列表做了要求,对返回值不做要求的原因.

五、C++和C语言相互调用

我们都知道C++支持C语言的大部分语法,C++和C语言可以相互调用吗?实际上是可以的,在一个大型程序中,有的部门可能使用的是C写的的函数,有的部门可能用的C++,要是他们不能相互使用那就打脸了.

1.创建静态库

我们可以把自己写的代码编译成一个静态库或者动态库,这里我以静态库举例,看看如何在VS中中创建一个静态库.

2.C++调用C

我们已经有了一个C语言的静态库,现在有一个C++的项目需要使用这个静态库,我们该如何使用呢?需要分为下面几个步骤

下面这两张图片都是修改环境的设置,我使用的是VS2013,其他的大概应该差不多,大家依次来修改就可以了.

到这里我们就可以调用C语言的静态库了,让我们来看看结果吧.

#include "../../Heap/Heap/heap.h"  //相对路径
int main()
{
	MyHeap myHeap;
	InitMyHeap(&myHeap);
	HeapPush(&myHeap, 1);
	HeapPush(&myHeap, 2);
	HeapPush(&myHeap, 3);
	Display(&myHeap);
	return 0;
}

这为什么报错?我们不是已经设置好了静态库了吗?实际上这种错误是很容易分析出来的,当C++去调用C语言的函数时,C++会自动修改函数名,当时C语言不会啊,所以他们就不会碰到一起,链接就会出错.

extern “C”

既然编译器不能自动识别C语言的函数名,我们告诉编译器一下不就可以了吗.extern “C” 就是这种作用.

有时候在C++工程中可能需要将某些函数按照 C 的风格来编译在函数前加 extern “C” ,意思是告诉编译器,
将该函数按照
 C 语言规则来编译。比如:tcmalloc是Google用C++实现的一个项目,他提供tcmallc()和tcfree
两个接口来使用,但如果是C项目就没办法使用,那么他就使用extern “C”来解决

extern "C"   // 告知这是C语言的函数声明
{
	#include "../../Heap/Heap/heap.h"
}
int main()
{
	MyHeap myHeap;
	InitMyHeap(&myHeap);
	HeapPush(&myHeap, 1);
	HeapPush(&myHeap, 2);
	HeapPush(&myHeap, 3);
	Display(&myHeap);
	return 0;
}

extern “C” 原理

我们需要来看看extern “C” 的原理,使用了extern “C” 后,在C++在进行编译的时候函数名字就依据C语言的方法来修改了,不在变成C++ 的规则.extern "C"可以单独修饰函数,也可以修饰一系列函数,使用代码块.

// test.h
#pragma once 
#include <iostream>
#include <stdio.h>
extern "C" void func(int a, double b);
//test.cpp

#include "test.h"
//写两个函数   函数形成重载
void func(int a, double b)
{
	printf("%d %lf", a, b);
}
//Mian.cpp

#include "test.h"
int main()
{
	func(10, 2.20);
	return 0;
}

3.C语言调用C++

那么C语言可以调用C++ 的吗?可以了,不过也需要一些段来完成.如何让C语言去识别C++的规则呢?这是我们需要考虑的.

我们已经把库改成的了C++的静态库了.

#include "../../Heap/Heap/heap.h"
int main()
{
	MyHeap myHeap;
	InitMyHeap(&myHeap);
	HeapPush(&myHeap, 1);
	HeapPush(&myHeap, 2);
	HeapPush(&myHeap, 3);
	Display(&myHeap);
	return 0;
}

我们无法让C语言的编译器去识别C++ 的函数的命名,那么我们是不是可以在函数一编译的时候就完成函数名依照C语言来说.这就很简单了.

但是即使是这样,C语言仍旧会报错,原因在于在头文件展开的时候,C语言根本不识别extern “C”,所以我们就需要条件编译了.

使用条件编译来修改的静态库的方法如下,需要再次编译.

//方法一
#ifdef __cplusplus    // C++独有的
	#define EXTERNC extern "C"
#else 
	#define EXTERNC
#endif


EXTERNC extern void InitMyHeap(MyHeap * pHeap);

EXTERNC extern void HeapPush(MyHeap* pHeap, HPDataType x);
EXTERNC extern bool IsFull(MyHeap* pHeap);
EXTERNC extern bool IsEmpty(MyHeap* pHeap);
EXTERNC extern int HeapSize(MyHeap* pHeap);
EXTERNC extern void adjustDown(MyHeap* pHeap);
EXTERNC extern void adjustUp(MyHeap* pHeap);
EXTERNC extern void Display(MyHeap* pHeap);
EXTERNC extern HPDataType HeapTop(MyHeap* pHeap);
EXTERNC extern void HeapPop(MyHeap* pHeap);
//方法 二
#ifdef __cplusplus
extern "C"
{
#endif

	extern void InitMyHeap(MyHeap * pHeap);

	extern void HeapPush(MyHeap* pHeap, HPDataType x);
	extern bool IsFull(MyHeap* pHeap);
	extern bool IsEmpty(MyHeap* pHeap);
	extern int HeapSize(MyHeap* pHeap);
	extern void adjustDown(MyHeap* pHeap);
	extern void adjustUp(MyHeap* pHeap);
	extern void Display(MyHeap* pHeap);
	extern HPDataType HeapTop(MyHeap* pHeap);
	extern void HeapPop(MyHeap* pHeap);
#ifdef __cplusplus
}
#endif

这样就解决了.

注意,这里有一点需要注意的,当我们C语言调用C++静态库的时候,最起码我们实际需要的的那部分代码在extern "C"修饰的函数中不能发生重载.

六、C++ 注意事项

这个注意事项主要是依据extern "C"来谈的,有些比较偏僻的内容需要关注下.

1.extern "C"修饰的函数和一个函数完全一样

在extern "C"修饰的函数模块外面存在了一个完全一摸一样的的函数,这个编译器不会给通过的.

#ifdef __cplusplus
extern "C"
{
#endif 
	void func(int a, int b)
	{
		printf("C : %d %d\n", a, b);
	}
#ifdef __cplusplus
}
#endif 
//完全一样
void func(int a, int b)
{
	printf("C : %d %d\n", a, b);
}

2.extern "C"修饰的函数和一个函数构成重载

在extern "C"修饰的函数模块外面一个函数构成重载这种编译器可以通过的,但是extern "C"修饰的命名方法仍旧还是按照C语言的方式,构成重载的是C++的方式.

#include <iostream>
using namespace std;

#ifdef __cplusplus
extern "C"
{
#endif 
	void func(int a, int b)
	{
		printf("C : %d %d\n", a, b);
	}

#ifdef __cplusplus
}
#endif 

void func(double a, int b)
{
	printf("C++: %lf %d\n", a, b);
}

int main()
{
	func(1, 2);
	func(1.11, 2);
	return 0;
}

到此这篇关于C++ 函数重载背后的原理的文章就介绍到这了,更多相关C++ 函数重载内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++ 函数重载背后的原理

本文链接: https://www.lsjlt.com/news/148155.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++ 函数重载背后的原理
    目录一、函数重载二、函数重载的原理三、为何C++可以支持重载1.程序的编译链接四、C语言为何不支持重载1.C++为何可以支持函数重载五、C++和C语言相互调用1.创建静态库2.C++...
    99+
    2022-11-13
  • C++函数重载介绍与原理详解
    目录函数重载函数重载的概念函数重载的原理(名字修饰)总结:extern “C”函数重载 函数重载的概念 函数重载是函数的一种特殊情况,C++允许在同一作用域中...
    99+
    2022-11-12
  • C++之函数的重载
    目录一、C++ 函数重载1.重载规则2.匹配原则3.重载底层实现4.extern “C”总结一、C++ 函数重载 C++ 致力于简化编程,能过函数重名来达到简化编程的目的 1.重载规...
    99+
    2022-11-12
  • C++函数重载的定义与原因详解
    目录引例函数重载的定义函数重载规则为什么C不支持函数重载而C++可以内部名称总结引例 如果要求你只能通过print函数,即能打印字符串,又能打印一个整型。 虽然在C语言中我们可以通过...
    99+
    2022-11-13
  • C++重载的奥义之函数重载详解
    目录一、基本定义        二、应用举例        三、非函数重载的情况四、函数重载的使用原则...
    99+
    2023-05-16
    C++ 函数重载 C++ 函数 C++ 重载
  • C++中函数重载定义与原因是什么
    小编给大家分享一下C++中函数重载定义与原因是什么,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!引例如果要求你只能通过print函数,即能打印字符串,又能打印一个整型。虽然在C语言中我们可以通过 print_i 和prin...
    99+
    2023-06-29
  • 关于C++的重载运算符和重载函数
    目录C++重载运算符和重载函数C++ 中的函数重载C++ 中的运算符重载可重载运算符/不可重载运算符C++重载运算符和重载函数 C++ 允许在同一作用域中的某个函数和运算符指定多个定...
    99+
    2023-05-19
    C++重载运算符 C++重载函数
  • c++函数的重载怎么实现
    这篇文章主要讲解了“c++函数的重载怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“c++函数的重载怎么实现”吧!1.函数重载概述作用:函数可以相同,提高复用性函数重载必须满足的条件:...
    99+
    2023-06-29
  • c++核心编程之函数的重载
    目录1.函数重载概述2.函数重载的注意事项1.函数重载概述 ​作用​:函数可以相同,提高复用性 ​函数重载必须满足的条件​: 1​.同一个作用域下​2.​函数名称相同​3.函数​参...
    99+
    2022-11-13
  • C++作用域与函数重载的实现
    目录1、作用域1.1 作用域的作用1.2 作用域的分类1.3 static 、const2、 域作用限定符2.1 空间域的命名2.2 指定空间访问2.3 全局展开3、函数重载3.1 ...
    99+
    2023-02-03
    C++作用域 C++函数重载
  • C++函数重载的细节图文详解
    前言:如果不想看论证,可以直接点击总结,跳转到最后 1、使用重载函数时,如果数据类型不匹配,C++尝试使用类型转换与形参进行匹配,如果转换后有多个函数能匹配上,编译器将报错; 论证如...
    99+
    2022-12-10
    c++函数重载例子 C++函数重载是什么 重载函数怎么写
  • MySQL索引背后的数据结构及算法原理
            本文(面对的是程序员而非专业数据库管理员DBA)以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题。特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也...
    99+
    2020-06-18
    MySQL索引背后的数据结构及算法原理
  • C++超详细分析函数重载的使用
    目录一、函数重载分析(上)1.1 重载的定义1.2 函数重载的定义1.3 函数重载需要满足的条件1.4 编译器调用重载函数的准则1.5 函数重载的注意事项1.6 小结二、函数重载分析...
    99+
    2022-11-13
  • C++函数重载、隐藏与覆盖重写的精通指南
    前言 对于C++函数而言,多个函数如果同名会有很多有意思的事情,从声明的作用域来看,在横向上同一个可访问作用域里面的同名函数可以进行重载;而纵向上作用域对于父子继承的派生类来说,同样...
    99+
    2022-11-13
  • C++中的函数重载问题及解决方法
    C++中的函数重载问题及解决方法引言:函数重载是C++中一种非常强大的特性,它允许在同一个作用域内定义多个同名函数,但函数的参数类型、个数或顺序不同。这样可以根据不同的参数选择不同的函数执行,提高代码的灵活性和可读性。然而,在实际编程过程中...
    99+
    2023-10-22
    C++编程 函数重载问题 函数重载解决方法
  • C++函数重载、隐藏与覆盖重写的方法是什么
    这篇文章主要介绍了C++函数重载、隐藏与覆盖重写的方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++函数重载、隐藏与覆盖重写的方法是什么文章都会有所收获,下面我们一起来看看吧。1 函数重载定义:C+...
    99+
    2023-06-29
  • C++中fork函数的使用及原理
    目录fork函数的基本概况fork函数做的工作fork函数之后fork函数的基本概况 fork() 函数调用成功之后,会有两个返回值。当前进程,也就是父进程返回子进程的 pid,子进...
    99+
    2023-05-19
    C++ fork函数 C++ fork
  • C++模板函数重载的相关介绍和用法
    本篇内容介绍了“C++模板函数重载的相关介绍和用法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!实例化后的模版函数如果和某个非模版函数的调用...
    99+
    2023-06-17
  • C++简明讲解缺省参数与函数重载的用法
    目录一、缺省参数1.1缺省参数概念1.2缺省参数分类二、函数重载2.1函数重载概念2.2名字修饰一、缺省参数 缺省参数形象来说就是"备胎"。 1.1缺省参数概念 ...
    99+
    2022-11-13
  • C++中函数重载问题及解决方法的概述
    C++中函数重载问题及解决方法的概述在C++中,函数重载是指在同一个作用域中可以定义多个同名但参数类型或参数个数不同的函数。函数重载的好处在于能够提高代码的可读性和灵活性,使得开发人员可以根据不同的需求使用同一个函数名进行操作。然而,函数重...
    99+
    2023-10-22
    C++ 函数重载 问题解决方法
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作