C++ 引用

        引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。

引用和指针

        引用很容易与指针混淆,它们之间有三个主要的不同:

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。

        注意:引用的本质是指针常量(指针常量(Pointer Constant)和常量指针(Constant Pointer)是两个容易混淆但不同的概念,后面解释)。例如下面一段代码:

#include<iostream>
using namespace std;

int main()
{
	int a = 10;
	int& ref = a;//自动转换为:int* const ref = &a;指针常量的指针指向不可更改,这也是引用不可更改的原因

	ref = 20;//ref是引用,编译器会自动转换为:*ref=20;

	cout << "a: " << a << endl;
	cout << "ref: " << ref << endl;

	return 0;
}

        int& ref = a; 会自动转换为:int* const ref = &a;而指针常量的指针指向不可更改,这也是引用不可更改的原因 。

        还有一点需要注意的是引用一个常量的情况:

/*错误,因为引用需要一个合法的内存空间,因此这一行是错误的 */
int& ref -4 = 10;   

/* 正确,加入const之后,编译器会优化代码,这一行相当于:int temp=10; const int& ref=temp; */
const int& ref = 10; 

创建引用

        假设变量名称是变量附属在内存位置中的标签,则可以把引用当成变量附属在内存位置中的第二个标签。因此,可以通过原始变量名称或引用来访问变量的内容。例如:

int i = 17;
int & r = i;
double d = 30.0;
double & s = d;

        注意:语句中的&运算符不是地址运算符,而是将 i 的类型声明为int &,即指向int变量的引用。

        在声明中,& 读作引用。因此,第一个声明可以读作 "r 是一个初始化为 i 的整型引用",第二个声明可以读作 "s 是一个初始化为 d 的 double 型引用"。下面的实例使用了 int 和 double 引用:

#include <iostream>

using namespace std;

int main()
{ 
	/* 声明简单的变量 */ 
	int i = 5;
	double j = 10.0;

	/* 声明引用变量 */ 
	int & m = i;
	double & n = j;

	cout << "Value of i : " << i << endl;
	cout << "Value of i reference : " << m << endl;

	cout << "Value of j : " << j << endl;
	cout << "Value of j reference : " << n << endl;

	return 0;
}

        编译和执行上面的代码:

Value of i : 5
Value of i reference : 5
Value of j : 10
Value of j reference : 10

        引用通常用于函数参数列表和函数返回值。

把引用作为参数

        使用引用来实现引用调用函数:

#include <iostream>

using namespace std;

void swap(int& x, int& y);  // 函数声明

int main()
{
	/* 局部变量声明 */ 
	int a = 100;
	int b = 200;

	cout << "交换前,a 的值:" << a << endl;
	cout << "交换前,b 的值:" << b << endl;

	swap(a, b);  //调用函数来交换值

	cout << "交换后,a 的值:" << a << endl;
	cout << "交换后,b 的值:" << b << endl;

	return 0;
}

void swap(int & x, int & y)  // 函数定义
{
	int temp; 

	temp = x; // 保存地址 x 的值 
	x = y;    // 把 y 赋值给 x 
	y = temp; // 把 x 赋值给 y  

	return;
}

         编译和执行上面的代码:

交换前,a 的值:100
交换前,b 的值:200
交换后,a 的值:200
交换后,b 的值:100

把引用作为返回值

        使用引用替代指针,会使 C++ 程序更容易阅读和维护。函数可以返回一个引用,方式与返回一个指针类似。

        当函数返回一个引用时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边。例如,请看下面这个简单的程序:

#include <iostream>

using namespace std;

double vals[] = { 10.1, 12.6, 33.1, 24.1, 50.0 };

/* 返回第i个元素的引用,ref是一个引用变量,ref引用 vals[i] */ 
double& setValues(int i) 
{
    double& ref = vals[i];

    return ref;   
}

int main()
{
    cout << "改变前的值" << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << "vals[" << i << "] = ";
        cout << vals[i] << endl;
    }

    setValues(1) = 20.23; // 改变第 2 个元素
    setValues(3) = 70.8;  // 改变第 4 个元素

    cout << "改变后的值" << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << "vals[" << i << "] = ";
        cout << vals[i] << endl;
    }

    return 0;
}

         编译和执行上面的代码:

改变前的值
vals[0] = 10.1
vals[1] = 12.6
vals[2] = 33.1
vals[3] = 24.1
vals[4] = 50
改变后的值
vals[0] = 10.1
vals[1] = 20.23
vals[2] = 33.1
vals[3] = 70.8
vals[4] = 50

        注意:当返回一个引用时,要注意被引用的对象不能超出作用域。所以返回一个对局部变量的引用是不合法的,但是,可以返回一个对静态变量的引用。

int& func()
{
	int q;         // 若return q; 在编译时发生错误,因为局部变量q超出了作用域	
	static int x;  // 安全,x 在函数作用域外依然是有效的

	return x; 
}

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

  • 不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
  • 不能返回函数内部新分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况,会面临其它尴尬局面。例如,被函数返回的引用只是作为一 个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(函数内部新分配的内存)就无法释放,造成内存泄漏。
  •  可以返回类成员的引用,但最好是const。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。

指针常量 和常量指针

        指针常量(Pointer Constant)和常量指针(Constant Pointer)是两个容易混淆但不同的概念。在C和C++编程中,理解它们的区别对于写出安全和高效的代码非常重要。

指针常量(Pointer to Constant)

        指针常量是指指针本身的值(即存储的地址)可以改变,但指针所指向的数据内容不能改变。换句话说,你不能通过这个指针修改它所指向的数据。

const int *ptr;

        在这个例子中,ptr是一个指向const int的指针。这意味着你不能通过ptr来修改它所指向的int值。例如:

const int value = 10;  
const int anotherValue = 20;  
const int *ptr = &value;  
  
// *ptr = 20; // 错误:不能通过ptr修改value  
ptr = &anotherValue; // 正确:可以改变ptr指向的地址

常量指针(Constant Pointer)

        常量指针是指指针本身的值(即存储的地址)不能改变,但指针所指向的数据内容可以改变。换句话说,你不能让指针指向另一个地址,但你可以通过这个指针修改它所指向的数据。

int *const ptr;

        在这个例子中,ptr是一个const指针,指向int。这意味着你不能改变ptr的值(即它所指向的地址),但你可以通过ptr来修改它所指向的int值。例如:

int value = 10;  
int anotherValue = 20;  
int *const ptr = &value;  
  
*ptr = 20; // 正确:可以通过ptr修改value  
// ptr = &anotherValue; // 错误:不能改变ptr指向的地址

既是常量指针又是指针常量

        有时候你可能需要一个既是常量指针又是指针常量的指针。这意味着既不能改变指针所指向的地址,也不能通过指针修改所指向的数据内容。

const int *const ptr;

        在这个例子中,ptr是一个指向const int的const指针。这意味着你不能改变ptr的值(即它所指向的地址),也不能通过ptr来修改它所指向的int值。例如:

const int value = 10;  
const int *const ptr = &value;  
  
// *ptr = 20; // 错误:不能通过ptr修改value  
// ptr = &anotherValue; // 错误:不能改变ptr指向的地址

        理解这些概念对于编写健壮和高效的C/C++代码非常重要,尤其是在处理复杂的指针操作和内存管理时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值