参数传递
将引用作为函数参数的特点:
- 在被调函数中对形参变量的操作就是对其相应的目标对象的操作。
- 在内存中没有产生实参的副本,它是直接对实参进行操作;而使用一般变量传递函数的参数,当发生函数调时,需要给形参分配存储单元,如果传递的是对象,还要调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般的变量传递参数的效率和所占空间都好。
- 虽然使用指针也能达到引用的效果,但是在函数调用时同样要给形参分配存储单元,而且程序容易产生错误,阅读性差。
传递指针的引用
例子:
void ptrswap(int *&v1, int *&v2){
int *tmp = v2;
v2 = v1;
v1 = tmp;
}
形参int *&v1的定义从右往左理解:v1是一个引用,与指向int类型对象的指针相关联。也就是说,v1只是传递进ptrswap函数的任意int型指针的别名。
内联函数
用inline修饰,有两种形式:
- 在类中定义的成员函数全部默认为内联函数,可以显示地加上inline标识符,或者不加。
- 普通函数声明或定义前加上inline成为内联函数。
在编译时,调用内联函数的地方,将不进行函数调用,而是使用函数体替换调用处的函数名,形式类似宏替换,这种替换成为内联扩展,可以消除函数调用时的时间开销。
注意,宏定义与内联函数的区别:1. 宏定义是在预处理阶段进行代码替换,而内联函数是在编译阶段插入代码;2. 宏定义没有类型检查,而内联函数有类型检查。
函数重载
函数重载用来命名一组功能相似的函数,这样减少函数名的数量,避免名字空间的污染。
函数重载,同名,参数个数不同,或参数类型不同,不能仅仅基于不同的返回类型而重载。
函数模板与泛型
泛型编程与面向对象编程一样,有依赖于每种形式的多态性。模板是泛型的基础。
例子:模板加内联
#include <iostream>
using namespace std;
template <typename T>
inline T AddNums(const T &a, const T &b){
return a + b;
}
int main()
{
cout << AddNums(3, 5) << "," << AddNums(3.2, 5.3) << endl;
return 0;
}
例子:类模板
template <class Type> class Queue {
public:
Queue();
void push(const Type &);
private:
// ...
};
使用类模板时,必须为模板形参显示制定实参。Queue<int> q;
函数的递归
递归必须满足两个条件:
- 递归表达式(递归体)
- 边界条件(递归出口)
递归的精髓在于能否将原始问题转换为属性相同但规模较小的问题。
递归的优点是减少程序的代码量,缺点是通常情况下效率不高。
例:斐波那契递归实现
int Fib(n) {
if(n == 0)
return 0;
else if(n == 1)
return 1;
else
return Fib(n-1)+Fib(n-2);
}
将递归转换为非递归,通常需要借助栈来实现。
附:斐波那契动态规划实现
int DPFib(int n){
int ret = 0,dpA, dpB;
if(n==1)
return 1;
else if(n==2)
return 2;
dpA = 1;
dpB = 2;
for(int i = 3; i <= n; ++i){
ret = dpB + dpA;
dpA = dpB;
dpB = ret;
}
return ret;
}