第八章——函数探幽

C++内联函数

内联函数是为了提高程序运行速度所做的一项改进。常规函数与内联函数的主要区别不在于编写方式,而在于C++编译器如何将它们组合到程序中。

对于 C++内联函数,编译器将使用相应的函数代码替换函数调用,程序无需跳到另一个位置处执行代码,再跳回来。因此内联函数的运行速度比常规函数稍快,但代价是需要占用更多的内存。所以应该有选择地使用内联函数。

 要使用这项特性,必须采用下述措施之一:

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

程序员请求将函数作为内联函数,编译器并不一定会满足这种请求,它可能认为该函数过大或函数调用了自己(内联函数不能递归),因此不将其作为内联函数

#include<iostream>
using namespace std;
inline double square(double x) { return x * x; }
int main()
{
	double a, b;
	double c = 13.0;

	a = square(5.0);
	b = square(4.5 + 7.5);
	cout << "a = " << a << " ,b = " << b << endl;
	cout << "c = " <<square(c)<< endl;
	return 0;
}

 

 引用变量

C++新增了一种复合类型——引用变量。引用是已定义的变量的别名(另一个名称)。(例如,如果将twain作为clement变量的引用,则可以交替使用twain和clement来表示该变量)。引用变量的主要用途是用作函数的形参,通过将引用变量用作参数,函数将使用原始数据而不是其副本。 

创建引用变量

 C和C++使用&符号来指示变量的地址。C++给&符号赋予了另一个含义,将其用来声明引用。

例如要将rodents作为rats变量的别名,可以这样做:

int rats;
int & rodents = rats;

 其中&不是地址运算符,而是类型标识符的一部分。就像char*指的是指向char指针,int& 指的是指向int的引用。

上述引用声明允许将rats和rodents互换——它们指向相同的值和内存单元

#include<iostream>
using namespace std;
int main()
{
	int rats = 101;
	int& rodents = rats;
	cout << "rats = " << rats << " at " << &rats<<endl;
	cout << ",rodents = " << rodents <<" at "<<&rodents<< endl;

	rodents++;
	cout << endl;
	cout << "rats = " << rats << " at " << &rats << endl;
	cout << ",rodents = " << rodents << " at " << &rodents << endl;
}

 

注意区分&在下面两个语句中的作用是不一样的

int &rodents = rats;
cout << "at" << &rodents << endl;

第一个语句中&运算符是引用的意思;第二个语句中&运算符是取地址运算符

必须在声明引用时将其初始化,一旦与某个变量关联起来,就一直效忠于它。

 将引用用作函数参数

引用经常被用作函数参数,使得函数中的变量名称为调用程序中的变量别名,这种传递参数的方式称为按引用传递。

 下面用三种方法交换两个变量的值。

#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 wallet1 = 300;
	int wallet2 = 350;
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << endl;

	cout << "Using reference to swap contents:\n";
	swapr(wallet1, wallet2);
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << endl;

	cout << "Using pointers to swap contents again:\n";
	swapp(&wallet1, &wallet2);
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << endl;

	cout << "Trying to use passing by value:\n";
	swapv(wallet1, wallet2);
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << 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;
}

 应尽可能使用const

将引用参数声明为常量数据的引用的理由有三个:

  • 使用const可以避免无意中修改数据的编程错误
  • 使用const使函数能够处理const和非const实参,否则将只能接受非const数据
  • 使用const引用使函数能够正确生成并使用临时变量

何时使用引用参数?

 使用引用参数的主要原因有两个:

  • 程序员能够修改调用函数中的数据对象
  • 通过传递引用而不是整个数据对象,可以提高程序的运行速度

当数据对象较大时(如结构和类对象),第二个原因最重要,这些也是使用指针参数的原因。

那么什么时候应使用引用、什么时候应使用指针呢?什么时候应按值传递呢?下面是一些指导原则:

对于使用传递的值而不作修改的函数。

  • 如果数据对象很小,如内置数据类型或小型结构,则按值传递
  • 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针
  • 如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率,这样可以节省复制结构所需的时间和空间
  • 如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用。因此传递类对象参数的标准方式是按引用传递

对于修改调用函数中数据的函数

  • 如果数据对象是内置数据类型,则使用指针
  • 如果数据对象是数组,则只能使用指针
  • 如果数据对象是结构,则使用引用或指针
  • 如果数据对象是类对象,则使用引用

函数重载 

 函数多态是C++在C语言基础上新增的功能。函数多态(重载)让程序员能够使用多个同名的函数。多态和重载这两个术语是同一回事,我们通常使用函数重载。

C++使用上下文来确定要使用的重载函数版本

函数重载的关键是函数的参数列表——也称为函数特征标。如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则它们的特征标相同,而变量名是无关紧要的;如果参数数目或参数类型不同,则特征标也不同,例如,可以定义一组原型如下的print()函数:

void print(const char *str, int width);     #1
void print(double d, int width);            #2
void print(long l, int width);              #3
void print(int i, int width);               #4
void print(const char *str);                #5

使用print()函数时,编译器将根据所采取的用法使用有相应特征标的原型:

print("Pank",15);        // use #1
print("Syrup");          // use #5
print(1999.0,10);        // use #2
print(1999,12);          // use #4
print(1999L,15);         // use #3

 虽然函数重载很诱人,但是不要滥用。仅当函数基本上执行相同的任务,但使用不同形式的数据时,才应采用函数重载。

函数模板

 现在的C++编译器实现了C++新增的一项特性——函数模板。函数模板是通用的函数描述,也就是说它们使用泛型来定义函数,其中的泛型可用具体的类型(如 int 或 double)替换。通过将类型作为参数传递给模板,可使编译器生成该类型的函数。

假如已经定义了一个交换两个int值的函数,但是现在需要交换两个double值,则一种方法是复制原来的代码,并用double替换所有的int。如果需要交换两个char,可以再一次使用同样的技术。

C++的函数模板功能能自动完成这一过程

函数模板允许以任意类型的方式来定义函数,例如可以这样建立一个交换模板

Template<typename AnyType>
void Swap(AnyType &a,AnyType &b)
{
    AnyType temp;
    temp=a;
    a=b;
    b=temp;
}

 第一行指出要建立一个模板,并将其类型命名为AnyType。关键字template和typename是必需的,除非可以使用关键字class代替typename。另外必须使用尖括号。模板并不创建任何函数,而只是告诉编译器如何定义函数。

猜你喜欢

转载自blog.csdn.net/yangSHU21/article/details/131641748