主要内容
- 内联函数
- 引用变量
- 默认参数
- 函数重载
- 函数模板
内联函数
内联函数和常规函数的主要区别是C++编译器如何将他们组合到程序中。
常规函数:程序在调用常规函数时, 使程序跳到另一个地址,函数结束后返回主程序。
内联函数:C++中编译器使用相应的代码块替换内联函数调用,因此程序无需跳到另外一个地址执行函数,相比于常规函数,节省了时间,但是浪费了内存。
应用内联函数
预备:在函数声明前加上关键字inline;在函数定义前加上关键字inline。
inline double square(double x) {return x * x;}
注:内联函数定义不适合占用多行,会让费较多内存;内联函数不能递归。
内联函数和常规函数一样——按值传递参数,看下例:
...
inline double square(double x) {return x * x;}
...
b = square(4.5 + 7.5);
...
输出: b = 144
————————————————————————————————————————————————————————————————————————————
C语言中:
...
#define SQUARE(X) X*X
...
b = SQUARE(4.5 + 7.5);
...
输出: b = 4.5 + 7.5 * 4.5 + 7.5
C语言使用预处理器语句#define来提供宏——内联函数的原始实现。
引用变量
引用是已定义变量的别名。引用变量的主要用途是用作函数的形参。通过引用变量用作参数,函数将使用原始数据,而不是其副本。
引用与指针差别之一:必须在声明引用时将其初始化。
#include<iostream>
using namespace std;
void swapr(int & a, int & b);
void swapp(int *p, int *q);
void swapv(int a, int b);
int main()
{
int wa1 = 300;
int wa2 = 350;
cout << "wallet1 = $" << wa1;
cout << " wallet2 = $" << wa2 << endl;
cout << "Using reference to swap contents:\n\n";
swapr(wa1, wa2);
cout << "wallet1 = $" << wa1;
cout << " wallet2 = $" << wa2 << endl;
cout << "Using pointers to swap contents:\n\n";
swapp(&wa1, &wa2);
cout << "wallet1 = $" << wa1;
cout << " wallet2 = $" << wa2 << endl;
cout << "Tring to use passing by value:\n\n";
swapv(wa1, wa2);
cout << "wallet1 = $" << wa1;
cout << " wallet2 = $" << wa2 << endl;
return 0;
}
void swapr(int & a, int & b)
{
int temp;
temp = a;
a = b;
b = temp;
}
void swapp(int *p, int *q)
{
int temp;
temp = *p;
*p = *q;
*q = temp;
}
void swapv(int a, int b)
{
int temp;
temp = a;
a = b;
b = temp;
}
- 在swapr(wa1, wa2)中,a和wa1指向相同的值和地址,即它们可以相互替换,b和wa2亦如此(引用的主要用途)
- 在swapp(&wa1, &wa2)中,传递的是地址,通过改变指针所指向的内容能够实现参数数值互换;
- 在swapv(wa1, wa2)中,函数创建参数副本进行操作,并不改变参数本身。
引用与指针差别之二:指针需要在函数使用p、q的整个过程中使用解除引用运算符*
临时变量
如果实参与const类引用参数不匹配,C++将生成临时变量。
生成临时变量的两种情形:实参的类型正确,但不是左值;实参的类型不正确,但可以转换为正确的类型。
左值参数是可被引用的数据对象,如变量、数组元素、结构成员等。(C语言中最初指可出现在赋值语句左边的实体)
生成临时变量的示例:c5 、 c6 、 c7
————————————————————————————————————————————————
double refcube(const double &ra)
{
return ra * ra * ra;
}
double side = 3.0;
double *pd = &side;
double &rd = side;
long edge = 5L;
double lens[4] = { 2.0, 5.0, 3.0, 6.0 };
double c1 = refcube(side);
double c2 = refcube(lens[2]);
double c3 = refcube(rd);
double c4 = refcube(*pd);
double c5 = refcube(edge);
double c6 = refcube(7.0)
double c7 = refcube(side + 10.0);
- c5中,edge的类型不正确;
- c6 和 c7中,参数7.0和side+10.0的类型正确,但是没有名称,编译器将生成一个临时匿名变量。
临时变量只在函数调用期间存在,此后编译器便可以随意删除。
void swapr(int & a, int & b)
{
int temp;
temp = a;
a = b;
b = temp;
}
调用:
long m = 3, n = 4;
swapr(m, n);
类型不匹配,因此编译器将生成两个临时变量,将他们初始化为3和4,然后交换临时变量的内容,而m、n保持不变。
返回引用需要注意的问题,返回引用需要避免返回函数终止时不再存在的内存单元引用。
#include<iostream>
#include<string>
using namespace std;
string version1(const string & s1, const string &s2);
const string & version2(string & s1, const string &s2);
const string & version3(string & s1, const string &s2);
int main()
{
string input;
string copy;
string result;
cout << "Enter a string: ";
getline(cin, input);
copy = input;
cout << "Your string as entered: " << input << endl;
result = version1(input, "***");
cout << "Your string enhanced: " << result << endl;
cout << "Your orginial string: " << input << endl;
result = version2(input, "###");
cout << "Your string enhanced: " << result << endl;
cout << "Your orginial string: " << input << endl;
cout << "Resetting orginial string.\n";
input = copy;
result = version3(input, "@@@");
cout << "Your string enhanced: " << result << endl;
cout << "Your orginial string: " << input << endl;
return 0;
}
string version1(const string & s1, const string &s2)
{
string temp;
temp = s2 + s1 + s2;
return temp;
}
const string & version2(string & s1, const string &s2)
{
s1 = s2 + s1 + s2;
return s1;
}
const string & version3(string & s1, const string &s2)
{
string temp;
temp = s2 + s1 + s2;
return temp;
}
程序报错
原因是在函数version3()中,temp是临时变量,只存在于该函数内,函数运行结束后会被释放,因此指向temp的引用的内容不可预料,调用出错。
默认参数
默认参数指的是当函数中省略了实参时自动使用的一个值。
带参数列表的函数,必须从右向左添加默认值,也就是说,要为某个参数设置默认值,则必须为它右边的所有参数提供默认值。
int harpo(int n, int m = 4, int j = 5);
beeps = harpo(2); //有效
_____________________________________________________
beeps = harpo(1, 8); //= harpo(1, 8, 5)
_____________________________________________________
beeps = harpo(1, 8, 7); //默认参数未使用
函数重载
函数多态(函数重载)让程序员能够使用多个同名的函数。
函数重载的关键是函数的参数列表——也成为函数特征标。C++允许定义名称相同的函数,条件是它们的特征标不同。
void print(const char * str, int width);
void print(int i, int width);
void print(const char * str);
函数模板
函数模板是通用的和拿书描述,它们使用泛型来定义函数,其中泛型可用具体的类型来替换。
template<typename, Anytype> //可以class代替typename
void swap(Anytype &a, Anytype &b)
{
Anytype temp;
temp = a + b;
return temp;
}
在调用时,函数swap(m, n)会根据m,n的类型来确定Anytype。
重载的模板
template<typename, T>
void swap(T &a, T &b);
***********************************
template<typename, T>
void swap(T *a, T *b, int n );
显式具体化
struct job
{
char name[40];
double salary;
int floor;
};
template <> void swap<job>(job &, job &);
实例化和具体化
实例化:
template void swap<int>(int, int);
____________________________________
具体化:
template <> void swap<int>(int &, int &);
template <> void swap(int &, int &);
若有多个原型,编译器在选择时,优先级:非模板版本 -> 显式具体化 -> 模板版本