【C++】C++入门详解 I【C++入门 这一篇文章就够了】(下)

简介: 【C++】C++入门详解 I【C++入门 这一篇文章就够了】

五、缺省参数

(一) 缺省参数 概念

缺省参数是 声明或定义函数时 为函数的 参数指定一个缺省值

在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参 。

void Func(int a = 0)
{
 cout<<a<<endl;
}
int main()
{
 Func();     // 没有传参时,使用参数的默认值
 Func(10);   // 传参时,使用指定的实参
return 0;
}



(二) 缺省参数分类

  • 全缺省参数
void Func(int a = 10, int b = 20, int c = 30)
 {
     cout<<"a = "<<a<<endl;
     cout<<"b = "<<b<<endl;
     cout<<"c = "<<c<<endl;
 }
  • 半缺省参数
    半缺省参数必须 从右往左 依次来给出,不能间隔着给
void Func(int a, int b = 10, int c = 20)
 {
     cout<<"a = "<<a<<endl;
     cout<<"b = "<<b<<endl;
     cout<<"c = "<<c<<endl;
 }


注意:

  1. 缺省参数不能在 函数声明 和 定义 中同时出现
    如果 声明与定义位置同时出现 ,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值。
//a.h
  void Func(int a = 10);
  // a.cpp
  void Func(int a = 20)
 {}
  1. 缺省值必须是 常量 或者 全局变量
  2. C语言不支持(编译器不支持)



六、函数重载

C不支持同名函数,C都是靠函数名来识别函数的,但功能类似,只是因为 形参列表 (参数个数 或 类型 或 类型顺序)不同 ,而因此要开辟很多不同的函数名。这是一件很麻烦且效率低下的事情。

对此,C++做出改进,提出了函数重载的概念。



(一) 函数重载概念

函数重载:是函数的一种特殊情况,C++允许在 同一作用域中 声明几个功能类似同名函数,这

些同名函数的 形参列表(参数个数 或 类型 或 类型顺序)不同 ,常用来处理实现 功能类似数据类型不同 的问题。

  • [ 返回值可用可不用 ]
    会出现不知道该调用谁。



(二)函数重载

(1)参数类型不同

#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
 cout << "int Add(int left, int right)" << endl;
 return left + right;
}
double Add(double left, double right)
{
 cout << "double Add(double left, double right)" << endl;
 return left + right;
}
int main(){
 Add(10, 20);
 Add(10.1, 20.2);
}


(2)参数个数不同

// 2、参数个数不同
void f()
{
 cout << "f()" << endl;
}
void f(int a)
{
 cout << "f(int a)" << endl;
}
int main()
{ 
 f();                                             ☆//f()则不知道该调用 f()还是f(int a)  
 f(10);     //f(10)可以很明确的是传给f(int a);
}


(3)参数类型顺序不同

// 3、参数类型顺序不同
void f(int a, char b)
{
 cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
 cout << "f(char b, int a)" << endl;
}
int main()
{
 f(10, 'a');
 f('a', 10);
 return 0;
}



(三)函数重载 底层原理_名字修饰(name Mangling)

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

在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理编译汇编链接

  1. 预处理(.i 文件)
    预处理指令,头文件展开


  1. 编译(.s 文件)
    语法分析,词法分析,语义分析,符号汇总

(语法束)检查语法,生成汇编代码 [指令级代码]( 给我们看的 )



2.1 函数调用在编译阶段,call(地址)

[ 只有声明 ( 但编译器让它过 ),没有地址 ]

[会 在链接阶段,通过根据汇编阶段生成的.o文件符号表( 找到对应函数名的地址 )将call()里面的地址进行链接 ]



2.2 并且将参数带入进行修饰产生 [ 函数名修饰规则 ]

由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下面我们使用了g++演示了这个修饰后的名字。

通过下面我们可以看出 gcc(C)的函数修饰后名字不变。而 g++(C++)的函数修饰后变成_Z+函数长度+函数名+类型首字母

  • 采用C语言编译器编译后结果

    结论:在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。
  • 采用C++编译器编译后结果
    结论:在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。
  • Windows下名字修饰规则

对比Linux会发现,windows下vs编译器对函数名字修饰规则相对复杂难懂,但道理都是类似的,我们就不做细致的研究了

【扩展学习:C/C++函数调用约定和名字修饰规则–有兴趣好奇的同学可以看看,里面有对vs下函数名修饰规则讲解】

C/C++ 函数调用约定

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

如果两个函数 函数名和参数是一样 的,返回值不同不构成重载 的,因为调用时编译器没办法区分

返回值可用可不用 ,会出现不知道该调用谁的情况。



  1. 汇编( 可重定位目标文件.o 文件)
    3.1 形成符号表。(汇编调用函数时,才会call 地址 ,因此符号表就是在这时产生的)
    符号表:
    形式 “ 函数名 地址 ” [ 函数名 和 地址 的映射 ]

    3.2 汇编指令 -> 二进制指令 [ 转换成二进制的机器码( CPU 能认识的 )] -> test.o



  1. 链接
    合并段表
    符号表的合并 和 符号表的重定位
    合并到一起,链接一些没有确定的函数地址等 [ 用函数名去找地址( 函数名修饰规则 )]

实际项目通常是由多个头文件和多个源文件构成,而通过C语言阶段学习的编译链接,我们可以知道,【当前a.cpp中调用了b.cpp中定义的Add函数时】,编译后链接前,a.o的目标文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。那么怎么办呢?

所以 链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就会到b.o的符号表中找Add的地址,然后链接到一起

那么链接时,面对Add函数,链接接器会使用哪个名字去找呢?这里就通过我们前面 编译阶段讲的 每个编译器都有自己的 函数名修饰规则来找。

目录
相关文章
|
29天前
|
存储 C++ 容器
C++入门指南:string类文档详细解析(非常经典,建议收藏)
C++入门指南:string类文档详细解析(非常经典,建议收藏)
38 0
|
29天前
|
编译器 C++
C++入门指南:10分钟带你快速了解模板究竟是什么(建议收藏!!)
C++入门指南:10分钟带你快速了解模板究竟是什么(建议收藏!!)
33 0
|
29天前
|
存储 编译器 C语言
C++入门: 类和对象笔记总结(上)
C++入门: 类和对象笔记总结(上)
34 0
|
1月前
|
编译器 Linux C语言
C++第二弹---C++入门(中)
C++第二弹---C++入门(中)
|
1月前
|
Java 程序员 Maven
【C/C++ CommonAPI入门篇】深入浅出:CommonAPI C++ D-Bus Tools 完全使用教程指南
【C/C++ CommonAPI入门篇】深入浅出:CommonAPI C++ D-Bus Tools 完全使用教程指南
58 0
|
1月前
|
算法 安全 C++
【C++ 泛型编程 入门篇】深入探索C++的numeric_limits:全面理解数值界限(一)
【C++ 泛型编程 入门篇】深入探索C++的numeric_limits:全面理解数值界限
45 0
|
1月前
|
存储 算法 测试技术
【C++ 泛型编程 入门篇】深入探索C++的numeric_limits:全面理解数值界限(二)
【C++ 泛型编程 入门篇】深入探索C++的numeric_limits:全面理解数值界限
32 0
|
3天前
|
设计模式 存储 Java
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
|
3天前
|
存储 C++
C++从入门到精通:1.1.4基础语法之控制流
C++从入门到精通:1.1.4基础语法之控制流
|
3天前
|
存储 编译器 C++
C++从入门到精通:1.1.2基础语法之数据类型
C++从入门到精通:1.1.2基础语法之数据类型