内联函数
使用内联函数,需要采取以下两种措施之一:
- 在函数声明之前加上关键字inline
- 在函数定义之前加上关键字inline
通常,会选择直接省略函数原型,将整个函数定义加上 inline
关键字之后放在函数原型的位置。比如直接:
inline double square(double x) { return x*x; }
内联函数在编译的时候,编译器会用相应的代码直接替换函数调用,在运行过程中无需进行常规函数调用的跳转等操作。也就是说时间开销更小,但是内存开销更大。一般使用在函数内容比较少,并且调用次数很多的情况。
引用变量
相当于是一个变量的别名,常在传递变量参数的时候使用,也可以改变变量的值。
void cube(float &ra){
ra *= ra * ra;
}
// 这样的写法将直接改变a的值
// 如果只想读取而不改变参数的值,那么可以使用常量引用
double refcube(const double &ra);
// 返回引用 v.s. 普通返回
struct free_throw{
std::string name;
int made;
};
// 返回引用,将会返回target的引用
free_throw &accumulate(free_throw &target, const free_throw &source);
free_throw &accumulate(free_throw &target, const free_throw &source){
target.made += source.made;
return target;
}
// 返回target的拷贝
free_throw &accumulate(free_throw &target, const free_throw &source);
free_throw &accumulate(free_throw &target, const free_throw &source){
target.made += source.made;
return target;
}
// 右值引用,引用一个临时变量,显然是不能修改的。主要是为了减少复制,提高效率。
double & add(double &target, double && source){
target = target + source;
return target;
}
double t=10.0;
double x = add(t, 5+3); //是合法的,5+3的结果不用进行复制
注意
- 按照引用传递,其实参只能是变量,而不能是表达式或者其他东西
- 基类的引用可以指向派生类对象。也就是说形参是基类引用,可以传入派生类。
引用最大的作用是用于类和结构体这类的变量。想要直接在函数中修改对象的值,那么就可以直接使用引用,而不想要改变的话,就加入 const
。
返回引用的效率更高,而且返回值是一个变量的本体,可以作为赋值语句的左值。
函数重载(函数多态)
cpp中允许定义定义相同名称的函数,但是要求他们拥有不同的特征标,即他们的参数数量/参数类型不一样。
函数的参数列表就是函数的特征标,包括参数的数量,类型和排列顺序,都要求一样,才能说函数的特征标是一样的。
注意:
- 使用重载函数的时候,最好让参数类型完全匹配,如果需要强制类型转换而又存在多种转换的可能性,程序将报错。
函数模板
如果使用相似的功能,但是需要不同类型的变量,这个时候可以使用函数模板这个功能。
// 其中 template 和 typename 关键字是必须的,但是参数名是可以自定义的
// prototype
template <typename AnyType>
void Swap(AnyType &a, AnyType &b);
// declaration
template <typename AnyType>
void Swap(AnyType &a, AnyType &b){
AnyType temp;
temp = a;
a = b;
b = temp;
}
// 使用
int a=1, b=2;
Swap(a, b);
普通定义,函数模板,显示具体化
针对一些比较复杂的类型,比如说自己定义的 struct 或者 class,想要实现特定的操作,可能函数模板提供的功能并不适用,可以使用显式具体化。
上面的函数会直接交换两个引用所指向的对象。但是可能我们只是想交换结构体中的两个值,比如下面的情况,可以使用函数模板
struct job{
std::string name;
int salary;
};
template <typename T>
void Swap(T &, T &);
template<> void Swap<job>(job &, job &);
int main(){
job good_job = {"mechmind", 250};
job bad_job = {"ByteDance", 400};
Swap(good_job, bad_job);
std::cout << good_job.name << std::endl;
std::cout << good_job.salary;
}
template <typename T>
void Swap(T &a, T &b){
T temp;
temp = a;
a = b;
b = temp;
}
template<> void Swap<job>(job &a, job &b){
std::string temp;
temp = a.name;
a.name = b.name;
b.name = temp;
}
此时由于输入的两个实参是 job 类型,因此优先使用了具体化的函数。定义显式具体化函数的如下:
template<> returnType FuncName<VariableName>(variables)
其中,FuncName后面的变量名是可以省略的。
但是如果显示的定义了非模板类的函数,也就是 void Swap(job &, job &);
,那么程序会优先选择非模板类的函数。也就是说优先级是 非模板类函数>显示具体化>模板类函数