内联函数

使用内联函数,需要采取以下两种措施之一:

  • 在函数声明之前加上关键字inline
  • 在函数定义之前加上关键字inline

通常,会选择直接省略函数原型,将整个函数定义加上 inline 关键字之后放在函数原型的位置。比如直接:

  1. inline double square(double x) { return x*x; }

内联函数在编译的时候,编译器会用相应的代码直接替换函数调用,在运行过程中无需进行常规函数调用的跳转等操作。也就是说时间开销更小,但是内存开销更大。一般使用在函数内容比较少,并且调用次数很多的情况。

引用变量

相当于是一个变量的别名,常在传递变量参数的时候使用,也可以改变变量的值。

  1. void cube(float &ra){
  2. ra *= ra * ra;
  3. }
  4. // 这样的写法将直接改变a的值
  5. // 如果只想读取而不改变参数的值,那么可以使用常量引用
  6. double refcube(const double &ra);
  7. // 返回引用 v.s. 普通返回
  8. struct free_throw{
  9. std::string name;
  10. int made;
  11. };
  12. // 返回引用,将会返回target的引用
  13. free_throw &accumulate(free_throw &target, const free_throw &source);
  14. free_throw &accumulate(free_throw &target, const free_throw &source){
  15. target.made += source.made;
  16. return target;
  17. }
  18. // 返回target的拷贝
  19. free_throw &accumulate(free_throw &target, const free_throw &source);
  20. free_throw &accumulate(free_throw &target, const free_throw &source){
  21. target.made += source.made;
  22. return target;
  23. }
  24. // 右值引用,引用一个临时变量,显然是不能修改的。主要是为了减少复制,提高效率。
  25. double & add(double &target, double && source){
  26. target = target + source;
  27. return target;
  28. }
  29. double t=10.0;
  30. double x = add(t, 5+3); //是合法的,5+3的结果不用进行复制

注意

  • 按照引用传递,其实参只能是变量,而不能是表达式或者其他东西
  • 基类的引用可以指向派生类对象。也就是说形参是基类引用,可以传入派生类。

引用最大的作用是用于类和结构体这类的变量。想要直接在函数中修改对象的值,那么就可以直接使用引用,而不想要改变的话,就加入 const

返回引用的效率更高,而且返回值是一个变量的本体,可以作为赋值语句的左值。

函数重载(函数多态)

cpp中允许定义定义相同名称的函数,但是要求他们拥有不同的特征标,即他们的参数数量/参数类型不一样。

函数的参数列表就是函数的特征标,包括参数的数量,类型和排列顺序,都要求一样,才能说函数的特征标是一样的。

注意

  • 使用重载函数的时候,最好让参数类型完全匹配,如果需要强制类型转换而又存在多种转换的可能性,程序将报错。

函数模板

如果使用相似的功能,但是需要不同类型的变量,这个时候可以使用函数模板这个功能。

  1. // 其中 template 和 typename 关键字是必须的,但是参数名是可以自定义的
  2. // prototype
  3. template <typename AnyType>
  4. void Swap(AnyType &a, AnyType &b);
  5. // declaration
  6. template <typename AnyType>
  7. void Swap(AnyType &a, AnyType &b){
  8. AnyType temp;
  9. temp = a;
  10. a = b;
  11. b = temp;
  12. }
  13. // 使用
  14. int a=1, b=2;
  15. Swap(a, b);

普通定义,函数模板,显示具体化

针对一些比较复杂的类型,比如说自己定义的 struct 或者 class,想要实现特定的操作,可能函数模板提供的功能并不适用,可以使用显式具体化。

上面的函数会直接交换两个引用所指向的对象。但是可能我们只是想交换结构体中的两个值,比如下面的情况,可以使用函数模板

  1. struct job{
  2. std::string name;
  3. int salary;
  4. };
  5. template <typename T>
  6. void Swap(T &, T &);
  7. template<> void Swap<job>(job &, job &);
  8. int main(){
  9. job good_job = {"mechmind", 250};
  10. job bad_job = {"ByteDance", 400};
  11. Swap(good_job, bad_job);
  12. std::cout << good_job.name << std::endl;
  13. std::cout << good_job.salary;
  14. }
  15. template <typename T>
  16. void Swap(T &a, T &b){
  17. T temp;
  18. temp = a;
  19. a = b;
  20. b = temp;
  21. }
  22. template<> void Swap<job>(job &a, job &b){
  23. std::string temp;
  24. temp = a.name;
  25. a.name = b.name;
  26. b.name = temp;
  27. }

此时由于输入的两个实参是 job 类型,因此优先使用了具体化的函数。定义显式具体化函数的如下:

  1. template<> returnType FuncName<VariableName>(variables)

其中,FuncName后面的变量名是可以省略的。

但是如果显示的定义了非模板类的函数,也就是 void Swap(job &, job &);,那么程序会优先选择非模板类的函数。也就是说优先级是 非模板类函数>显示具体化>模板类函数