inline&reference

C++内联函数

传统函数:当我们调用函数的时候,其实是将该指令的内存地址保存下来,并将函数参数复制到堆栈。当函数运行完之后再跳回去。这样来回跳跃会加大开销。因此还有另一种函数,叫做内联函数。

内联函数:简单来说就是将函数的代码替换函数调用,这样就不用跳到其他地方执行,但是如果有10个地方调用了这个函数,那么就会有10个函数代码的拷贝。

  • 在函数声明前加上inline
  • 在函数定义前加上inline

Warning: 如果内联函数过大或者调用了自己(不支持递归),那么编译器不会将其作为内联函数。并不是所有的编译器启用了这个特性。

内联与宏

inline关键字是C++新增的特性。C语言则使用#define。但C语言中时、是通过文本替换而不是传递参数。

1
2
3
#define SQUARE(X) X*X
a = SQUARE(5 + 1);
// a = 5 + 1 * 5 + 1 not a = 6 * 6

引用变量

基本概念:引用是已定义的变量的别名。使用&符号表示引用。

1
2
int i;
int & another = i;//alias for i

int&表示指向int的引用,上述表示i和another指向相同的值和内存单元。如果改变了another,那么i也会改变。
引用其实就是另一个变量的完美复制品,除了名称不一样其他一模一样,表现在指针中则是:

1
int & i = rats;

等同于

1
int * const pr = &rats;

引用和指针最大的区别就是引用在声明的时候必须初始化。

引用用作函数参数

也就是将某种类型的引用作为参数传入函数。在代码方面,如果使用value传递的话会有一个变量的copy,而引用的则不会有两个变量,只会有两个名称。之后在函数中不管怎么处理都只是在操作这个copy而没有改变他的原始值。

如果我们定义了一个函数的参数是引用,那么则必须传一个变量进去,传入表达式则是不规范的。例如:

1
2
void square(int & i);
square(x + 3);// INVALID

当然有的编译器不会报错,只是弹一个warning出来,那是因为如果实参和引用参数不匹配的话就会生成临时变量。并且只有当参数是const引用时才会这么做。
如果参数是const类型,那么在以下情况会生成临时变量

  • 实参的类型正确,但不是左值。
  • 实参的类型不正确,但可以转换为正确的类型。

左值其实就是指处于等号左边的值,那么什么样的值可以放等号左边呢,自然是变量,引用等等。像字面常量,表达式则都属于非左值。如下例:

1
2
3
4
double refcube(const double & ra)
{
return ra * ra * ra;
}

1
2
3
4
5
double side = 3.0;
long edge = 5L
double c1 = refcube(edge);//临时变量,因为edge类型与参数不匹配
double c2 = refcube(7.0);//临时变量,非左值,字面常量
double c3 = refcube(side + 3.0);//临时变量,非左值,表达式

何时使用引用参数

  • 函数中的数据对象需要被修改
  • 数据较大时需要提高程序的运行速度。

第二个原因有点类似于指针,那么什么时候使用指针,什么时候使用引用呢:

  • 如果数据对象很小,则按值传递。
  • 如果数据对象是数组,那么使用指针,同时也是唯一的选择。
  • 如果是较大的数据结构则使用指针或引用。
  • 如果是类对象,则使用const引用。

默认参数

也很简单,就是在函数定义的时候给参数一个默认值。

1
char * open(int n = 1)

但是有个规矩那就是必须从右向左添加默认值。

函数重载

其实就是同一个函数,但是参数类型或者数量不同叫做函数重载。在java中是必须严格按照参数类型或者数量来调用函数的,但是在c++中如果调用的函数不与任何函数原型匹配,那么就会尝试使用标准类型转换强制进行匹配。

1
2
3
4
5
6
7
8
9
10
void test(int i = 1);

int main(int argc, const char * argv[]) {
test(2.2);
return 0;
}
void test (int i)
{
cout << i << endl;
}

1
Result:2

而关于const也可以用于重载函数,不过只有在修饰的参数是引用或者指针的时候才可以。

函数模版

简单来说就是使用泛型来定义函数,编译器会按照模版创建对应的函数,例如有个函数的作用是交换传入的两个参数,那么不管传入是int还是double都可以使用同一个函数模版。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
template <typename T>
void Swap(T &a,T &b);
using namespace std;

int main(int argc, const char * argv[]) {
int i = 10;
int j = 30;
Swap(i,j);
cout << i << endl;
cout << j << endl;
double d1 = 2.2;
double d2 = 4.4;
Swap(d1, d2);
cout << d1 << endl;
cout << d2 << endl;
return 0;
}
template <typename T>
void Swap(T &a,T &b) {
T temp;
temp = a;
a = b;
b = temp;
}