亲宝软件园·资讯

展开

C++函数重载

格式化、、 人气:1

前言

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

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

函数重载

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;
    }
}

感谢大家支持!!!

加载全部内容

相关教程
猜你喜欢
用户评论