函数重载
缺省参数
在定义或者声明一个函数的时候,给它的形参赋上一个默认值,调用这个函数的时候,如果没有把实参传入,函数就会使用我们指定的缺省参数,如果传入实参,就会使用传入的参数。
缺省参数可分为
- 全缺省参数
在这个函数中,给所有的形参都指定了默认值。 - 半缺省参数
在这个函数中,只给一部分的形参指定了默认值。
注意: 缺省参数的设置必须是从右向左的
特性
- 缺省参数的设置必须是从右向左的
- 不能在函数的声明和定义同时设置缺省参数
- 缺省参数的给定值必须是常量或者是全局变量
- C语言中不支持缺省参数
函数重载
相同作用域下,函数名相同,参数列表不同(形参个数,类型,顺序的不同)的函数,就是函数重载。
注意:函数重载和函数的返回值无关
void func(int a, int b);
void func(int a, double b);
void func(double a, double b);
void func(double a, int b);
void func(int b);
//以上这几个函数构成函数重载
编译器在编译代码期间,需要对函数的实参进行推演,根据推演的结果进行对应函数的调用
注意:有该函数存在,直接调用,如果不存在类型完全匹配的函数,则编译器会进行隐式类型转换,如果存在类型匹配的函数则调用,如果不存在(两种情况:1.没有类型匹配的函数 2.产生二义性),则编译失败
#include <iostream>
using namespace std;
int Add(int x, int y)
{
return x + y;
}
double Add(double x, double y)
{
return x + y;
}
int main()
{
int i = 10;
double d = 2.0;
cout << Add(i, d) << endl;
return 0;
}
编译结果如下图
因为int类型可以隐式转换为double类型,double类型可以隐式转换为int类型,编译器不知道该调用哪个函数,产生了二义性
底层实现原理是由于C语言和C++的函数命名规则不同
以下图片是在linux下运行的过程
从图中可以看出,C语言中函数名就是我们自己取得函数名
从上图我们可以看出,C++的函数命名后面会跟形参类型
不同系统和编译器下函数命名风格可能不同,主要区别就是C++的函数命名后面会跟形参类型,C语言的函数命名后面不跟形参类型
引用
引用相当于给一个变量取了一个别名,并没有新定义一个变量。 编译器不会给引用变量分配内存空间,引用变量与被引用的实体共用一块内存空间
特性
- 引用在定义的时候必须初始化
- 一旦引用了某个实体以后,就不可以再引用其他实体
- 一个变量可以有多个引用
三种传参方式的区别
传值 | 传地址 | 传引用 | |
---|---|---|---|
优点 | 可以对外部实参起到保护作用 | 可以通过形参修改外部实参,不需要对实参进行拷贝,传参效率高,节省空间 | 可以通过形参修改外部实参,不需要对实参进行拷贝,传参效率高,节省空间 |
缺点 | 不可以通过形参修改外部实参,因为形参是实参的一份拷贝;传参的效率低下,浪费空间 | 在不需要修改实参的情况下误操作,修改了实参,可以用const修饰,避免此类情况发生;需要判空,避免操作野指针或NULL;代码可读性较差 | 可能会误操作修改实参,可以用const修饰 |
下面是一些在C++中传参时的建议
内置类型 | 自定义类型 |
---|---|
如果不需要修改实参,尽量使用传值或者传引用+const;如果需要修改实参,建议使用传引用 | 建议使用传引用或传引用+const |
指针与引用的区别
- 在概念上,引用定义的是一个别名,指针定义的是一个的地址
- 引用在引用了一个实体后就不可以引用别的实体,指针在任意时候都可以指向其他同类型的地址
- 引用在定义的时候必须初始化,指针不是
- 只有NULL指针,没有空引用
- 有多级指针但是没有多级引用
- 指针自加是向后偏移一个类型的大小,引用自加是给引用加1
- sizeof的意义不同,sizeof(引用)的大小是引用的实体类型的大小,sizeof(指针)的大小是地址空间所占字节数,在32位平台下始终是4字节
- 引用的安全性比指针高
注意:引用和指针在底层的实现方式是完全相同的,引用就是按照指针的方式实现的
内联函数
宏的优缺点
宏常量 | 宏函数 | |
---|---|---|
优点 | 一改全改;宏常量名字具有一定意义 | 宏函数不是真正的函数,在预处理阶段,预处理器会把宏函数展开,减少了函数调用参数压栈、开辟栈帧返回等开销,效率提高 |
缺点 | 宏定义没有类型,不会参与到类型检测中去,导致代码的安全性不高,并且报错的时候定位不准确 | 需要加很多的括号区分;代码安全性不高;不能调试,代码膨胀;宏函数具有副作用 |
宏函数的副作用:
#include <stdio.h>
#define MAX(a,b) ((a) > (b)? (a): (b))
int main()
{
int a = 10;
int b = 20;
cout << MAX(a, b) << endl;
cout << MAX(++b, a) << endl;
return 0;
}
原本我们期待的结果是20 21,但是打印出来的是20 22;这是由于宏函数直接替换,即(++b) > (a) ? (++b) : (a),把++b运算了两次
C++如何解决宏的缺陷
宏常量:用const常量代替,并且有类型,更加安全
宏函数:inline函数替换
inline函数概念
在C++中,被inline关键字修饰的函数就是内联函数。
inline函数特性
- 在编译阶段,编译器会把内联函数直接展开,少了函数调用开销,提高运行速率
- inline是一个建议性的关键字,当修饰函数是,建议编译器把被inline函数直接展开;一般情况下,建议代码短但是被调用频繁的函数作为内联函数,递归函数不能作为内联函数
- inline函数具有文件作用域