文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C++深入浅出讲解函数重载

2024-04-02 19:55

关注

前言

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。

比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!”

函数重载

1.1 函数重载的概念

函数重载:

  1. 它是函数的一种特殊情况,C++允许在同一作用域中同一作用域中声明几个功能类似的同名函数
  2. 函数重载的关键是函数的参数列表,也称为“函数特征标”
  3. 这些同名函数的形参列表(参数个数、类型和顺序(不同类型的顺序))必须不同,常用来处理实现功能类似数据类型不同的问题
  4. 函数重载也是多态的一种,多态指的是“有多种形式”
//C语言不支持重载,C++支持重载
int Add(int left, int right)
{
   return left+right;
}
double Add(double left, double right)
{
   return left+right;
}
int Add(int left, double right)
{
   return left+right;
}
int Add(double left, int right)
{
   return left+right;
}
int main()
{
   Add(10, 20);
   Add(10.0, 20.0);
   Add(10, 20.0);
   Add(10.0, 20.0)
   return 0;
}

下面两个函数属于函数重载吗?

short Add(short left, short right)
{
   return left+right;
}
int Add(short left, short right)
{
   return left+right;
}
int main()
{
   Add(10, 20);
   Add(10, 20);
   return 0;
}

代码解析:

  1. 上述代码中的两个函数不属于函数重载
  2. 因为重载的形参列表(参数个数、类型和顺序)必须不同
  3. 函数重载与函数返回值的类型无关,并且在函数调用时,也是无法识别它的

1.2 函数重载的意义

意义:

在C语言中,想要定义多个不同类型交换数据的子函数,需要不同的函数名来命名,比如SweapA、SweapB…等等

void SweapA(int *pa, int *pb)
{
   int temp = *pa;
   *pa = *pb;
   *pb = temp;
}
void SweapB(double *pa, double *pb)
{
   double temp = *pa;
   *pa = *pb;
   *pb = temp;
}
int main()
{
   int a = 10, b = 20;
   double c = 10.0, d = 20.0;
   SweapA(&a, &b);
   SweapB(&c), &d);
   return 0;
}
  1. 但是,在C++中,通过函数重载,只需要命名一次就可以了
  2. 虽然跟C语言一样要重复定义函数,但是后面会学到函数模板后,可以很好的解决这个重复定义问题
void Sweap(int *pa, int *pb)
{
   int temp = *pa;
   *pa = *pb;
   *pb = temp;
}
void Sweap(double *pa, double *pb)
{
   double temp = *pa;
   *pa = *pb;
   *pb = temp;
}
int main()
{
   int a = 10, b = 20;
   double c = 10.0, d = 20.0;
   Sweap(&a, &b);
   Sweap(&c), &d);
   return 0;
}

1.3 名字修饰(name Mangling)

名字修饰(name Mangling):

为什么C++支持重载,而C语言不支持呢?

在Linux下使用gcc和g++编译器演示函数名被修饰后的名字

采用C语言编译器编译后结果(反汇编)

结论:在Linux下,采用gcc编译完成后,函数名字的修饰没有发生改变

采用C++编译器编译后结果(反汇编)

结论:在Linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中

总结

gcc的函数修饰后名字不变。而g++的函数修饰后变成(_Z+函数长度+函数名+类型首字母)

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

Windows下名字修饰规则

结论:对比Linux会发现,windows下C++编译器对函数名字修饰非常奇怪,但道理都是一样的

扩展学习:C/C++函数调用约定和名字修饰规则

C++函数重载

C/C++的调用约定

接下来,再演示一个例子

f.h
#include <stdio.h>

void f(int a, double b);
void f(double b, int a);

f.cpp
#include "f.h"

void f(int a, double b);
{
   printf("%d %lf\n", a, b)
}

void f(double b, int a);
{
   printf("%lf %d\n", b, a)
}
Test.cpp
#include "f.h"

int main()
{
   f(1, 2.222);
   f(2.222, 1);
   return 0;
}

编译后,生成汇编指令;链接时,生成符号表

Linux下g++(C++)编译器的命名:

Linux下gcc(C)编译器的命名:

1.4 extern "C"

那么CPP是怎么调用C中的静态/动态库呢?(vs2022演示)

首先,我们用C来生成一个静态库或动态库

Test.h
#include <stdio.h>
void PrintArray(int* p, int n); //显示数组内容
void InsertSort(int* p, int n); //插入排序
Test.C
#include "Test.h"
void InsertSort(int* p, int n)
{
    for (int i = 0; i < n - 1; ++i)
    {
        int end = i;
        int tmp = p[end + 1];
        while (end >= 0)
        {
            if (tmp < p[end])
            {
                p[end + 1] = p[end];
                --end;
            }
            else
            {
                break;
            }
        }
        p[end + 1] = tmp;
    }
}

配置类型改成静态库后,生成解决方案,就得到后缀.lib文件了

在CPP项目中添加新的库目录(这个库是你生成的静态库的路径)

增加新的依赖项(依赖项为生成静态库的文件名+后缀"Test.lib")

做完这些准备后,我们来进行编译程序

extern "C"
{
    //"../"是在当前目录的上一个目录中找文件
    #include "../../Test/Test/Test.h"
}
#include <iostream>
using namespace std;
void TestInsertSort()
{
	int Array[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
	InsertSort(Array, sizeof(Array) / sizeof(Array[0]));
	for (int i = 0; i < 10; ++i)
		cout << Array[i] << " ";
	cout << " " << endl;
}
int main()
{
	TestInsertSort();
	return 0;
}

如果C想调用CPP的静态或动态库呢?

Test.h
#include <stdio.h>
#ifdef __cplusplus
      #define EXTERN_C extern "C"
#else 
      #define EXTERN_C
#endif
EXTERN_C void PrintArray(int* p, int n);
EXTERN_C void InsertSort(int* p, int n);
Test.cpp
#include "Test.h"
void PrintArray(int* p, int n)
{
    for (int i = 0; i < n; ++i)
    {
        printf("%d ", p[i]);
    }
    printf("\n");
}
void InsertSort(int* p, int n)
{
    for (int i = 0; i < n - 1; ++i)
    {
        int end = i;
        int tmp = p[end + 1];
        while (end >= 0)
        {
            if (tmp < p[end])
            {
                p[end + 1] = p[end];
                --end;
            }
            else
            {
                break;
            }
        }
        p[end + 1] = tmp;
    }
}

感谢大家支持!!!

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

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯