IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> ?关于C++之引用 -> 正文阅读

[C++知识库]?关于C++之引用

引用的本质是指针

int rats = 101;
int& alias = rats;
int* prats = &rats;
——————————————————————————
alias <=> *prats <=> rats
&alias <=> prats <=> &rats

alias和*prats都可以同rats互换,&alias和prats都可以同&rats互换。从这一点来说,引用看上去很像伪装表示的指针。
也就是说:

int & alias = rats;
实际上是下述代码的伪装表示:
int * const pr = &rats;// 【指针常量】

由于pr是指针常量(指向不能变,所指值能变),所以pr所指地址不变,即一直跟踪rats,能通过pr改变rats的值,直接改变rats的值也同步到(*pr),所以和引用的本质是一样的。
引用也可以再赋值,引用效忠的对象也可再赋值,但总之引用是作为别名一直效忠于rats变量,不易主!
引用是引用的对象的别名!


int rats;
int& rodents = rats; // 使rodents成为rats的别名

引用更接近指针常量,必须在创建时进行初始化,一旦与某个变量关联起来,就将一直效忠于它(不易主)。——地址与地址上存的值总相同。

假设程序员试图这样做:

int rats = 101;
int* pt = &rats;
int& rodents = *pt; // 一直效忠rats
int bunnies = 50;
pt = &bunnies;

将rodents初始化为*pt使得rodents指向rats。接下来将pt改为指向bunnies,并不能改变这样的事实,即rodents引用的是rats。

下图直观演示了按值传递与按引用传递的区别:

示例:用三种方式,交互两个int值

#include <iostream>
void swapr(int& a, int& b);   // a, b are aliases for ints
void swapp(int* p, int* q);   // p, q are addresses of ints
void swapv(int a, int b);     // a, b are new variables
int main() {
	using namespace std;
	int wallet1 = 300;
	int wallet2 = 350;
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << endl;
 
	cout << "Using references to swap contents:\n";
	swapr(wallet1, wallet2);   // pass variables
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << endl;
 
	cout << "Using pointers to swap contents again:\n";
	swapp(&wallet1, &wallet2); // pass addresses of variables
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << endl;
 
	cout << "Trying to use passing by value:\n";
	swapv(wallet1, wallet2);   // pass values of variables
	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;
}
wallet1 = $300 wallet2 = $350            <<原始数据
Using references to swap contents:       
wallet1 = $350 wallet2 = $300            <<值被交换了
Using pointers to swap contents again:
wallet1 = $300 wallet2 = $350            <<值又被交换了
Trying to use passing by value:
wallet1 = $300 wallet2 = $350            <<交换失败
int main() {
	double x = 3.0;
	cout << cube(x);
	cout << " = cube of " << x << endl;
	cout << refcube(x);
	cout << " = cube of " << x;
	return 0;
}
double cube(double a) {
	a *= a * a;
	return a;
}
double refcube(double& ra) {
	ra *= ra * ra;
	return ra;
}
27 = cube of 3
27 = cube of 27

为何要返回引用:
计算关键字return后面的表达式,并将结果返回给调用函数。从概念上说,这个值被复制到一个临时位置,而调用程序将使用这个值。

double m = sqrt(16.0);
cout << sqrt(25.0);

在第一条语句中,值4.0被复制到一个临时位置,然后被复制给m。在第二条语句中,值5.0被复制到一个临时位置,然后被传递给cout。

dup = accumalate(team, five);

如果accumulate()返回一个结构,而不是指向结构的引用,将把整个结构复制到一个临时位置,再将这个拷贝复制给dup。但在返回值为引用时,将直接把team复制到dup,其效率更高。

返回引用时最重要的一点是,应避免返回函数终止时不再存在的内存单元引用。应避免编写下面的代码:

const free_throws & clone2(free_throwns & ft) {
    free_throwns newguy; // first step to big error
    newguy = ft; // copy info
    return newguy; // return reference to copy
}

该函数返回一个指向临时变量(newguy)的引用,函数运行完毕后它将不再存在。同样,也应避免返回指向临时变量的指针。
为避免这种问题,最简单的方法是,返回一个作为参数传递给函数的引用。作为参数的引用将指向调用函数使用的数据,因此返回的引用也将指向这些数据。如下代码就是这样做的:

free_throws& accumulate(free_throws& target, const free_throws& source) {
	target.attempts += source.attempts;
	target.made += source.made;
	return target;
}

示例:不注意上面要避免的后果:

int& test(int&);
int main() {
	int x = 6;
	int& y = test(test(x));// test()函数运行完后返回的临时引用消失!因为临时引用无变量承载!
	cout << y;
	return 0;
}
int& test(int& i) {
	int tmp = 2 * i;// 局部临时变量
	return tmp;// {}块结束后,tmp变量被系统回收消失
}
有些系统或IDE输出:
-1717986920
有些报错:
Segmentation fault
另一些报错:
warning: reference to local variable 'tmp' returned [-Wreturn-local-addr]

当返回值是引用类型时,会返回该变量的地址。当返回值不是引用型时,编译器会专门给返回值分配出一块临时内存。
总之,绝不能将一个指向局部变量的引用类型值作为函数的返回值!
同样,将一个指向局部变量的指针作为函数的返回值是也有问题的!
程序试图引用已经释放的内存,就是大问题。

将const用于引用返回类型及参数:
避免在设计中添加模糊的特性,因为模糊特性增加了犯错的机会。

accumlate(dup, five) = four;// 直接将函数返回的引用赋值!

假设您要使用引用返回值,但又不允许执行像给accumulate()赋值这样的操作,只需将返回类型声明为const引用:

const free_throwns & accumlate(free_throwns & target, const free_throwns & source);

参数source类型也声明为const,让它成为“只读”。

当然,有时省略const确实有道理,在讨论的重载运算符<<就是一个这样的例子。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 12:43:52  更:2022-03-06 12:47:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:08:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码