第八章 函数探幽

主要内容

  • 内联函数
  • 引用变量
  • 默认参数
  • 函数重载
  • 函数模板

内联函数

内联函数和常规函数的主要区别是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, 87);		//默认参数未使用

函数重载

函数多态(函数重载)让程序员能够使用多个同名的函数。
函数重载的关键是函数的参数列表——也成为函数特征标。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 &);

若有多个原型,编译器在选择时,优先级:非模板版本 -> 显式具体化 -> 模板版本

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值