函数探幽(一)——内联函数,引用变量

1 内联函数

    编译过程的最终产品是可执行程序——由一组机器语言指令组成,运行程序时,操作系统将这些指令载入到计算机中,因此每条指令都有特定的内存地址。常规的调用函数过程是:执行到函数调用指令时,程序将在函数调用后立即储存该指令的地址,并将函数的参数复制到堆栈,跳到标记函数起点的内存单元,执行函数代码,然后跳回到地址被保存的指令处继续执行,这些过程在时间和空间方面都有开销。于是C++提供了另一种办法——内联函数,也就是说,编译器将使用相应的函数代码替换函数调用。如图所示:

    注意,那些函数适合内联函数:只有一行代码的小型、非递归函数(函数不能调用自己)。另外,应有选择性的使用内联函数,如果执行函数代码的时间比处理函数调用机制的时间长,则节省的时间将只占整个过程很小的一部分,如果代码执行时间很短,则内联调用就可以节省非内联调用使用的大部分时间,但是由于这个过程相当快,因此尽管节省了该过程的大部分时间,但节省时间的绝对值并不大,除非该函数经常被调用。

      内联函数定义和声明时使用关键字inline,语法形式如下:

      inline  类型标识符  被调函数名(含类型说明的形参表);

    下面举个内联函数的例子:

#include<iostream>
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);
	std::cout<<"a="<<a<<",b="<<b<<"\n";
    std::cout<<"c="<<c;
	std::cout<<",c squared = "<<square(c++)<<"\n";
	std::cout<<"Now c="<<c<<"\n";
	return 0;
}

程序输出为:

2 引用变量

我们先来看一段代码,主要就是要交换两个数的值,我们分别用引用,指针和按值传递的方法:

#include<iostream>
void swapr(int & a,int & b);
void swapp(int * p,int * q);
void swapv(int a,int b);
int main()
{
	using namespace std;
	int s1=300;
	int s2=350;
	cout<<"s1="<<s1;
	cout<<" s2="<<s2<<endl;

	cout<<"Using reference to swap contents:\n";
	swapr(s1,s2);
	cout<<"s1="<<s1;
	cout<<" s2="<<s2<<endl;

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

	cout<<"Trying to use passing by value:\n";
	swapv(s1,s2);
	cout<<"s1="<<s1;
	cout<<" s2="<<s2<<endl;

	return 0;
}

void swapr(int & a,int & b)//use references
{
	int temp;
	temp=a;
	a=b;
	b=temp;
}

void swapp(int * p,int * q)//use pointers
{
	int temp;
	temp=*p;
	*p=*q;
	*q=temp;
}

void swapv(int a,int b)//try using values
{
	int temp;
	temp=a;
	a=b;
	b=temp;
}

程序输出为:

           从输出的结果,我们可以看出,按引用和指针传递都实现了数据的交换,而按值传递没有实现。从程序来看,按引用传递swapr(s1,s2);和按值传递swapv(s1,s2);的代码是一样的,只有通过函数参数原型才能区分swapr(int & a,int & b);是按照引用传递的,另外地址运算符&使得按地址传递swapp(&s1,&s2);显得一目了然(类型声明int*p表明,p是一个int指针,因此与p对应的应为地址)。

    下面来讲一下引用变量,C,C++使用&符号来指示变量的地址。C++给&符号赋予了另一个含义,将其用来声明引用。例如要将rodents作为rats变量的别名,可以这样做 :

     很多人看到引用会想到指针,其实两者之间还是有区别的

     (1)创建区别

int rats;
int &rodents=rats;//rodents a reference
int * prats=&rats;//prats a pointer

(2)声明区别

引用必须在声明之初将其初始化。下面这样就不行:

int rat;
int & rodent;
rodent=rat;//no,you can't do this
引用,更接近于const指针,必须在创建时进行初始化,一旦与某个变量关联起来,就将一直效忠于它。看个例子:

#include<iostream>
int main()
{
	using namespace std;
	int rats=101;
	int & rodents=rats;

	cout<<"rats="<<rats;
	cout<<",rodents="<<rodents<<endl;
	cout<<"rats address"<<&rats;
	cout<<",rodents address"<<&rodents<<endl;

	int bunnines=50;
	rodents=bunnines;
	cout<<"bunnines="<<bunnines;
	cout<<",rats="<<rats;
	cout<<",rodents="<<rodents<<endl;
	cout<<"bunnies address"<<&bunnines;
	cout<<",rodents address"<<&rodents<<endl;

	return 0;
}
程序输出为:
引用非常适合于结构和类,而引入引用也主要是为了用于这些类型,而不是基本的内置类型。引用的典型例子:

(1)将引用用于结构

    如果job为结构,可以这样编写函数原型:void set_pc(job & ft);//use a reference to a structure;如果不希望函数修改传入的结构,可使用const:void set_pc(const job & ft);

(2)将引用用于类对象

     将类对象传递给函数时,C++通常的做法是使用引用。例如,可以通过使用引用,让函数将类string、ostream、istream、ofstream和ifstream等类的对象作为参数。举个例子:

#include<iostream>
#include<string>
#include <cctype>
using namespace std;
int display(string & str);

void main()
{
	string list;
	int a;
	cout<<"Enter a string (q to quit):";
	getline(cin,list);
	a=display(list);
	while(a==1)
	{
		cout<<"Next string(q to quit):";
		getline(cin,list);
		a=display(list);
	}
}

int display(string & str)
{
	char s;
	for (int i=0;i<str.length();i++)
	{
		if (str[i]!='q')
		{ 
			s=toupper(str[i]);
			cout<<s;
		}
		else
		{
			cout<<"Bye.";
			cout<<endl;
			return 0;
		}	
	}
	cout<<endl;
	return 1;	
}
程序输出为:

综上所述,那么何时应使用引用,什么时候应使用指针,什么时候应按值传递?

(1)如果数据对象很小,如内置数据类型或小型结构,则按值传递。

(2)如果数据对象为数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针。

(3)如果数据对象是较大的结构,则使用const指针或者const引用,以提高程序效率。这样可以节省复制结构所需要的时间和空间。

(4)如果数据对象时类对象,则使用const引用。类设计的语义常常要求使用引用,这是C++新增这项特性的主要原因。因此,传递类对象的标准方式是按引用传递。









 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值