概述
文章目录
- 1、缺省参数
- 1.1、概念
- 1.2、分类:
- 1.3、特性:
- 2、函数重载
- 2.1、概念
- 2.2、调用原理
- 2.3、底层实现原理
- 2.4、extern "C"
- 3、引用
- 3.1、概念
- 3.2、特性
- 3.3、三种传参方式区别
- 3.4、指针和引用的区别
- 4、内联函数
- 4.1、宏常量
- 4.2、宏函数
- 4.3、C++如何解决宏的缺陷
1、缺省参数
1.1、概念
在声明或定义函数时,给函数的参数设置一个默认值,当用户对函数进行调用时,如果传递了实参,则使用用户传递的实参;如果没有传递则使用默认值。
1.2、分类:
- 全缺省参数:所有参数都带有默认值;
- 半缺省参数:部分参数带有默认值。规则:必须从右往左依次给出。
1.3、特性:
- 缺省参数必须从右往左给出;
- 不能在函数声明和定义的位置同时给出;
- 缺省参数在提供时—常量||全局变量;
- C语言不支持。
2、函数重载
2.1、概念
相同作用域下,函数名字相同,参数列表必须不同(参数个数、参数类型、类型次序)。
注意:与函数的返回值类型是否相同没关系。
2.2、调用原理
编译器在编译代码期间,需要对函数的实参类型进行推演,根据推演的结果选择对应合适类型的函数进行调用。
注意:有该函数存在,则直接调用,如果不存在类型完全匹配的函数,则编译器会尝试进行隐式类型转换,转换完成后,如果有对应类型的函数,则进行调用,否则:编译失败(没有对应类型、调用二义性)。
2.3、底层实现原理
C++之所以能够支持函数重载,C语言不支持函数重载,是因为C++编译器和C语言编译器对函数名字的修饰规则不同。
注意:不同编译器对函数名修饰的细节可能不太相同,但大概原理是一样的。
(1)C语言编译器对函数名字的修饰规则:只是在函数名字前加 _
(2)C++编译器对函数名字的修饰规则:C++编译器将参数类型放到最终的名字中。例如:g++的修饰规则【_Z+函数长度+函数名+类型首字母】
2.4、extern “C”
在C++出现以前,很多代码都是C语言写的,而且很底层的库也是C语言写的,为了更好的支持原来的C代码和已经写好的C语言库,需要在C++中尽可能地支持C,而且在正常开发中,有些人擅长C语言,有些人擅长C++,那完全可能出现:C语言和C++混合起来编程。
在函数前加“extern “C”,意思就是告诉编译器,将该函数按照C语言规则来编译”
extern "C" int Add(int left, int right);
int main()
{
Add(1,2);
return 0; }
3、引用
3.1、概念
引用是一个别名,不是新定义一个变量,编译器不会给引用变量重新分配空间。引用变量与其引用地实体共用同一份内存空间。
3.2、特性
- 引用变量在定义时必须要初始化;
- 一个变量可以有多个引用;
- 引用变量一旦引用一个实体之后,就不能再去引用其它的实体。
3.3、三种传参方式区别
1、传值:
优点:可以对外部实参起到保护作用。
缺点:不能通过形参改变外部的实参,因为形参是实参的一份拷贝,在函数体中,修改形参实际修改的是实参的一份拷贝.
传参的效率低下,而且浪费空间。
2、传地址:
优点:可以通过形参改变外部的实参;不需要对实参进行拷贝,传参的效率高、节省空间。
缺点:在不需要通过形参改变外部实参的情况下,代码安全性不高。可以避免:const
指针:不安全,每次在使用时必须要判空,代码的可读性比较差。
3、传引用:
形参是实参的别名,对形参进行修改可以达到对实参的改变,对于不需要通过形参改变外部实参通过:const
传参效率高、节省空间、代码可读性高。
注意:在C++中,一般情况下传参时尽量使用引用。
内置类型:
- 如果需要通过形参改变外部的实参,尽量传递引用;
- 如果不需要通过形参改变外部的实参,使用传值、传引用+const
自定义类型:
传参都是用引用, T& 和 const T&
3.4、指针和引用的区别
说明:引用和指针在底层实现方式是完全相同的,引用就是按照指针的方式来实现的。
在概念和特性以及使用方式上的区别:
- 引用概念上定义一个变量的别名,指针存储一个变量地址;
- 引用在定义时必须初始化,指针没有要求;
- 引用在初始化时引用一个实体后,就不能再引用其它实体,而指针可以在任何时候指向任何一个同类型实体;
- 没有NULL引用,但有NULL指针;
- 在sizeof中含义不用,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节);
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小;
- 有多级指针,但没有多级引用;
- 访问方式不同,指针需要解引用,引用编译器自己处理;
- 引用比指针使用起来相对更安全。
4、内联函数
4.1、宏常量
优点:一改全改,代码的可维护性高;常量名字具有一定的含义—#define MAX_SIZE 100
缺点:宏常量没有类型的,不会参与到类型检测中,代码的安全性降低,而且一旦编译报错,报错的位置不准确。
4.2、宏函数
优点:宏函数不是一个真正的函数,在预处理阶段,预处理器已经将宏函数进行替换了,少了函数调用参数压栈,开辟栈帧,返回等的开销了,代码的运行效率提高。
缺点:
- 在实现时,可能会比较麻烦,要到处加括号;
#define MUL(A, B) A*B
int main()
{
int a = 1, b = 2, c = 3, d = 4;
cout<< MUL(a+b, c+d)<<endl; // 预处理阶段被替换成:a+b*c+d
return 0; }
- 宏函数也没有参数类型,不会有参数类型检测,安全性不高;
- 宏函数在预处理阶段会展开,不能调试;
- 宏函数具有副作用。
#define MAX(A, B) (((A) > (B))? (A) : (B))
int main()
{
int a = 10, b = 20;
cout<<MAX(++b, a)<<endl; // 期望输出21,但实际输出的是22,因为直接替换后,++b算了两次
return 0; }
4.3、C++如何解决宏的缺陷
1、宏常量:const常量,可以达到宏替换的效果,而且具有类型,更加安全。
int main()
{
const int a = 10;
int* pa = (int*)&a;
*pa = 100; // 此处已经将a的值修改为100
cout << *pa << endl; // 打印100
cout << a << endl; // 打印10,因为在编译阶段,常量a被替换为10
return 0; }
2、宏函数:解决方案—内联函数
内联函数:在C++中被inline关键字修饰的函数称为内联函数;如果成员函数在类中定义,编译器也可能会将其当成内联函数来处理。
特性:
- inline是一种空间换时间的做法,省去调用函数额外开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数;
- 在编译阶段,如果编译器将一个函数当成是内联函数的情况下,在编译代码时会对内联函数进行展开,少了函数调用的开销,程序的运行效果提高了;
- inline是一个建议性的关键字,当修饰函数时,建议编译器将该函数当成内联函数来进行处理,即:在编译阶段,将该函数展开。如果定义为内联函数体内有循环/递归等等,编译器优化时会忽略掉内联;
- inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到;
- inline函数具有文件作用域
最后
以上就是沉默黑夜为你收集整理的C++_函数重载&引用&内联函数的全部内容,希望文章能够帮你解决C++_函数重载&引用&内联函数所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复