0%

函数

内联函数

inline function在编译后实质上是函数代码块的替换,编译器不一定会实现inline function,如果编译器认为inline function太复杂或者有递归调用。inline function的链接性为内部链接,所以inline function的定义和声明不能放在不同的文件中。

引用类型作函数参数

如果函数的参数为引用类型,如果传递的参数类型正确但不是左值或者传递的参数类型不正确,在其可以转换为正确的类型的情况下,编译将会创建一个临时变量,而将引用参数引用到该临时变量上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
double refcube(const double &ra){
return re * ra * ra;
}

double side = 3.0;
double *pd = &side;
double &rd = side;

long edge = 5;
double lens[4] = {2.0, 5.0, 10.0, 12.0}

double c1 = refcube(side);//won't create temporary variable
double c2 = refcube(lens[2]);//won't create temporary variable
double c3 = refcube(rd);//won't create temporary variable
double c4 = refcube(*pd);//won't create temporary variable
double c5 = refcube(edge);//will create temporary variable
double c6 = refcube(7.0);//will create temporary variable
double c7 = refcube(side + 10.0);//will create temporary variable

带默认参数的函数

  • 如果要用为某个参数设置默认值,则必须为它右边的所有参数提供默认值
  • 函数定义中有默认参数,在函数实现中的函数头中可以不再写默认参数的值。

可变参数函数

1
int sum(int n, ...);

...代表可以接受任意类型的数据任意多个。

获取到可变参数列表的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int sum(int n, ...) {
va_list ap;
int sum = 0;
va_start(ap, n);
while (n > 0) {
int temp = va_arg(ap, int);
sum += temp;
--n;
}
va_end(ap);
return sum;
}

sum(3, 1, 2, 3);

1、va_list args; //定义一个可变参数列表
2va_start(args,n); //初始化args指向强制参数n的`下一个参数`
3va_arg(args,type); //`获取当前参数内容`并将args指向下一个参数
4va_end(args); //释放args

在使用va_arg宏时,要求type是POD(Plain Old Data)类型,能用 C 的 memcpy() 等函数进行操作的类、结构体就是 POD 类型的数据,所有基本数据类型都是POD。并且如果type和对应的参数不对的话会产生强制类型转换。如果类型转换失败就会将数据设置为0或者其他初始化的值。

函数重载

  • 函数的参数列表也称为函数特征标

  • 函数重载要求函数的参数数目或参数类型或参数的顺序不同,而参数名是无关紧要,且编译器在检查时不一定会将引用类型和本身类型视为同一特征标,但是如果调用重载函数存在二义性则编译器会报错。

  • 对于非引用传参,形参是否const是等价的。但是当使用引用传参时,有无const是不同的。使用指针传参时,指向const对象的指针和指向非const对象的指针做形参的函数是不同的

  • 只是函数返回值不同不能构成函数重载

  • 在类中,C++将区分常量和非常量函数(即函数本身是否为const)的特征标

  • 函数重载匹配原则

    • 最匹配原则
    • 如果没有匹配的将会进行类型强转后进行匹配,但是进行类型强转后进行匹配后有多个匹配的会产生报错;

函数模版

函数模版并没有创建一个函数,它只是告诉编译器如何创建如何创建一个函数,编译器在遇到使用模版函数的地方会将模版函数展开成具体的函数。

模版函数匹配原则:越具体越适配原则

1
2
3
4
5
6
template<typename T>
void func(T t);//函数1
void func(T *t);//函数2

int a = 0;
func(&a);//函数2更适配

decltype(x) y

decltype(x) y,用于说明y的类型和x的类型一样,decltype的运用场景大多是模版

1
2
template<typename T1, typename T2>
auto gt(T1 x, T2 y) -> decltype(x + y);

函数指针

函数指针的声明方式:

1
return_type (*pointer_name)(parameter);
  • *和pointer_name要用括号括起来,否则就变成了返回指针的函数。

  • 不能声明一个指向模版函数的指针,因为模版函数并没有实现真的函数,而只是说明如何声明函数

宏定义形式的函数

1
#define MAX(a, b) (a) > (b) ? (a) : (b)
注意要将参数用括号扩起来

有些时候用宏定义的代码被do { } while(0);包含了起来,例如:

1
2
3
#define MAX(a, b) do {    \
(a) > (b) ? (a) : (b); \
} while(0)

这是因为宏的处理是文本替换,有时候将宏用文本替换后代码就产生了语法错误,而使用do {} while(0)是为了避免由于文本替换后带来的语法错误,并保证宏函数无论如何都会执行一次。