C与C++的区别(3)——指针与引用

我们在学习c语言的时候,知道函数传参有两种,值传递和地址传递;而在C++中,多了一个引用的概念,引用就是给已存在的变量取了一个别名,编译器不会给引用开辟新的空间,与其引用的变量共用一块空间。

 

引用于指针的区别

引用:引用就是对某一变量的一个别名,对引用的操作对变量直接操作完全一致;

int a = 10;
int *p = a;
  • &在此不是求地址运算,而是起到标识作用。
  • 声明引用时,必须初始化。
  • 声明引用后,不能改变该应用的值。
  • 声明一个引用,不是定义了一个变量,它只表示该引用名是目标变量的一个别名,编译器不会为引用分配内存空间。
  • 无法引用一个数组,因为数组是若干个元素的集合,无法建立一个数组的别名。

指针:指向一块内存,可以通过解引用改变内存块的值。

int a;
int &ra =a;
  •  指针时一个实体,而引用是一个别名
  • 引用被初始化后不可改变,而指针可以改变
  • 指针在使用时需要解引用,而引用不需要解引用
  • 指针可为空,而引用不可以为空
  • sizeof 引用,得到的是所指变量(对象)的大小,而sizeof 指针,得到指针本身的大小
  • 指针可以指向一个数组,而引用不可以建立一个数组的别名。

 

引用的应用

(1)引用作为参数

在c中传参有两种形式:值传递和地址传递;我们知道在函数调用使用值传递时,要将参数压栈(有关函数调用压栈详见:https://blog.csdn.net/QX_a11/article/details/83959578),如果是大块数据作为参数传递的时候,采用指针的方式,这样可以避免大块内存全部压栈;在C++中引用指针后,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是直接对其相应的目标对象(主调函数)的操作。使用引用并没有在内存中产生副本。从而提高了效率。例如:

void swap(int &a,int &b)
{
	int temp = a;
	a = b;
	b = temp;
}
int main()
{
	int a = 10;
	int b = 20;
	swap(a,b);
	cout << a << b <<endl; 
}

如果既要利用引用提高程序的效率,又要保护传给函数的变量不被修改,这就要使用到常引用。

(2)常引用

要想保证目标变量不被修改则需加const,达到了引用的安全性;

引用声明:const 类型标识符 &引用名 = 目标变量名

int a = 10;
const int &ra = a;
//ra = 20;error
a = 20;

常引用也有其他方面的需求:

string foo();
void bar(string &s);

bar(foo());//非法
bar("Hello");//非法

在如上代码的foo()和“Hello”都会生成临时变量;原因是类型不匹配发生类型强转,进而生成临时变量;临时变量都是const修饰的常量。因此在调用点尝试将const类型转化为非const类型,这样是非法的。所以引用型参数尽量声明为const类型。

(3)引用作为返回值

格式:类型标识符 &函数名(形参列表)

用引用返回一个函数值的最大好处是,在内存中不产生返回值的副本

#include <iostream>
float temp; //定义全局变量temp
float fn1(float r); //声明函数fn1
float &fn2(float r); //声明函数fn2
float fn1(float r) //定义函数fn1,它以返回值的方法返回函数值
{
	temp = (float)(r*r*3.14);
	return temp;
}
float &fn2(float r) //定义函数fn2,它以引用方式返回函数值
{
	temp=(float)(r*r*3.14);
	return temp;
}
void main() //主函数
{
	float a=fn1(10.0); //第1种情况,系统生成要返回值的副本(即临时变量)
	/*float &b= fn1(10.0);*/ //第2种情况,可能会出错(不同 C++系统有不同规定)
	//不能从被调函数中返回一个临时变量或局部变量的引用
	float c=fn2(10.0); //第3种情况,系统不生成返回值的副本
	//可以从被调函数中返回一个全局变量的引用
	float &d=fn2(10.0); //第4种情况,系统不生成返回值的副本
	//可以从被调函数中返回一个全局变量的引用
	std::cout<<a<<c<<d;
} 

引用作为返回值,必须遵守以下规则:

  • 不能返回局部变量或临时变量的引用;局部变量会在函数返回后被销毁,引用没有实际的意义。
  • 不能返回函数内部new分配的内存的引用:虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其他尴尬的局面。例如,被函数返回的引用只是个临时变量,那么这个引用所指向的空间就无法释放
  • 引用于一些操作符的重载:流操作符<<和>>,这两个操作符都希望可以被连续使用,比如cout << a<<b<<endl;可供选择的返回值可以是流对象也可以是指向流对象的指针,如果返回流对象,则每次返归都会调用拷贝构造函数生成新的对象,显然是不可取的;那返回流对象的指针呢,返回流对象的指针又不可以连续使用;所以返回流对象的引用是重载流操作符的唯一选择。赋值运算符和流运算符一样,都希望可以被连续使用,a = b = 10;赋值操作符的返回值必须是一个左值,以便可以继续赋值。

 

引用的总结

1、引用是给某个变量取个别名,主要目的是在函数传递参数中,解决大内存块的传递效率和内存的使用情况;在传递中不产生副本,并且通过const的使用,保证了引用传递的安全性。

2、引用与指针的区别是,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。

3、引用使用在对流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数等

猜你喜欢

转载自blog.csdn.net/QX_a11/article/details/89603194