C++初阶 —— 函数重载

简介: C++初阶 —— 函数重载

【写在前面】

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

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

一、 函数重载概念

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

//1.参数个数
int Add(int x)
{}
int Add(int x, int y)
{}
//2.参数类型
int Add(int x, int y)
{}
int Add(int x, double y)
{}
//3.参数顺序
int Add(int x, float y)
{}
int Add(float y, int x)
{}

❗ 怎么调用 ❕

int Add(int left, int right)
{
  return left + right;
}
double Add(double left, double right)
{
  return left + right;
}
long Add(long left, long right)
{
  return left + right;
}
int main()
{
  //这里分别调用三种不同的函数
  Add(10, 20);//默认整型
  Add(10.0, 20.0);//浮点型
  Add(10L, 20L);//长整型
  return 0;
}

⚠ 注意

对于函数重载,如果你想调用某一函数,那么在传参的时候就必须写好对应参数的类型、个数、顺序,比如 float 数据,就要写 3f,因为这样它才能找到对应的函数调用

二、 名字修饰 (name Mangling)

❓ 为什么C++支持函数重载,而C语言不支持函数重载呢,以 Linux 环境下演示 ❔

注意这里就不细讲 Linux 的一些指令了,具体的我都写在或者将写在 《Linux专栏》里了

先在 Linux 下以两种编译方式编译函数重载的程序,这里有三个文件 :f.h、f.c、test.c

  ▶ 可以看到以 C 语言去编译函数重载报错了

  ▶ 可以看到以 C++ 去编译函数重载是可以的

在正式探究前我们先回忆下,注意 C/C++ 都有类似的过程,但肯定是有区别的,现在我们要找的就是那个区别

  这里我们对照着程序走一遍过程

然后再回到我们的问题

  ❓ C语言不支持函数重载 ❔

   C 编译器,直接用函数名关联,函数名相同时,无法区分

  ❗ 验证 ❕

   通过命令 objdump -S 去查看 C 编译生成的符号表

   通过命令 objdump -S 去查看 C++ 编译生成的符号表

  ❓ C++ 支持函数重载 ❔

   从上就可以看出对于函数重载 C++ 相对于 C 语言引入了某种规则

   C++ 引用了《函数名修饰规则 (Linux下)》不能直接用函数名,要对函数名进行修饰 (带入参数的特点修饰)

    📝 说明:

     1️⃣ _Z 是前缀

     2️⃣ 3 是函数名的长度

     3️⃣ Add 是函数名

     4️⃣ ii / dd 是函数参数类型的首字母,如果是 int* i,那么就是 pi

💨小结:

  C++ 是支持函数重载的,函数名相同,只要参数不同,修饰在符号表中的名字也不同,那么就能区分了

❗ Windows下函数名修饰规则 ❕

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

C++函数重载

C/C++ 函数调用约定

❓ 下面两个函数属于函数重载吗 (编译器能不能只实现返回值不同,就能构成重载) ❔

short Add(short left, short right)
{
  return left+right;
}
int Add(short left, short right)
{
  return left+right;
}

显然《函数名修饰规则》并不能让它们支持重载。

 ❓ 其次如果想自己定义《函数名修饰规则》让只有返回值不同的函数支持重载可以吗 ❔

  💨 编译器层面是可以区分的

   short Add; -> _Z3sAdd

   int Add; -> _Z3iAdd

  💨 语法调用层面有严重歧义

   Add(3, 5); ???

❓ 下面两个函数能形成函数重载吗?❔

void TestFunc(int a = 10)
{
  cout<<"void TestFunc(int)"<<endl;
}
void TestFunc(int a)
{
  cout<<"void TestFunc(int)"<<endl;
}

虽然两个函数的参数是缺省值和非缺省值,但是依旧不影响修饰出来的函数名,所以不能构成函数重载

三、 extern"C"

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

extern "C" int Add(int left, int right);
int main()
{
  Add(1,2);
  return 0; 
}

💨总结

  1️⃣ C++ 项目可以调用 C++ 库,也可以调用 C 的库,C++ 是直接兼容 C 的

  2️⃣ C 项目可以调用 C 库,也可以使用 extern"C" 调用 C++ 库 (C++ 提供的函数加上 extern"C")


相关文章
|
7天前
|
存储 安全 编译器
【C++入门】缺省参数、函数重载与引用(下)
【C++入门】缺省参数、函数重载与引用
|
6天前
|
编译器 C语言 C++
c++初阶------类和对象(六大默认构造函数的揭破)-3
c++初阶------类和对象(六大默认构造函数的揭破)
|
6天前
|
编译器 C语言 C++
c++初阶------类和对象(六大默认构造函数的揭破)-2
c++初阶------类和对象(六大默认构造函数的揭破)
|
6天前
|
存储 编译器 C语言
c++初阶-------类和对象-2
c++初阶-------类和对象
|
6天前
|
安全 编译器 C语言
C++初阶------------------入门C++(三)
C++初阶------------------入门C++(三)
|
6天前
|
存储 Linux 编译器
C++初阶------------------入门C++(二)
C++初阶------------------入门C++(二)
|
6天前
|
编译器 C语言 C++
C++初阶------------------入门C++(一)
C++初阶------------------入门C++(一)
|
7天前
|
编译器 C语言 C++
【C++入门学习指南】:函数重载提升代码清晰度与灵活性
【C++入门学习指南】:函数重载提升代码清晰度与灵活性
17 0
|
7天前
|
编译器 C语言 C++
【C++入门】缺省参数、函数重载与引用(上)
【C++入门】缺省参数、函数重载与引用
|
13天前
|
存储 编译器 对象存储
【C++基础(十)】C++泛型编程--模板初阶
【C++基础(十)】C++泛型编程--模板初阶
【C++基础(十)】C++泛型编程--模板初阶