C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++函数重载

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

作者:格式化、、

C++允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载(Function Overloading),借助重载,一个函数名可以有多种用途

前言

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

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

函数重载

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++函数重载内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文