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++知识库]C++在C语言上的拓展——引用

我们知道,C++就是C写的,C++也对C语言进行了拓展,那么,C++有哪些拓展呢?这些拓展跟C语言的关系又是什么呢?我们今天来讲讲引用。

目录

引用

引用的基本概念

引用到底是什么

引用在哪起作用

引用是怎么在地址空间里存储的

关于我用stdio.h写C++这件事


引用

引用的基本概念

引用给变量起别名。我们通过一个具体的例子来看一下引用的具体用法

我们想要实现一个变量交换的功能,在C语言里,我们会写出这样的代码:

// 交换a和b的值
void change(int *a, int *b){
        *b = *a+*b; // 现在a不变,b是a b的和
        *a = *b-*a; // 现在a是b-原来的a,b是a+b,所以现在的a是传进来的b
        *b = *b-*a; // 现在b是b-a,b是a+b,a是原来的b,所以b-a是原来的a
        return;
}

当我们调用的时候,我们会这样写:

change(&a, &b);

我们必须获取两个变量的地址,再在地址上更改数据才行。有没有不这么麻烦的方法?有,那就是引用

我们可以将change改为:

// 交换a和b的值
void change(int &a, int &b){
        b = a+b; // 现在a不变,b是a b的和
        a = b-a; // 现在a是b-原来的a,b是a+b,所以现在的a是传进来的b
        b = b-a; // 现在b是b-a,b是a+b,a是原来的b,所以b-a是原来的a
        return;
}

我们只需要写:

change(a, b);

就可以完成调用

引用到底是什么

要知道引用是什么,主要有两种思路。即:引用是在预处理的时候起作用的(类似宏定义)或引用是在编译的时候起作用的(类似变量)

引用在哪起作用

首先我们来看引用是否在预处理的时候起作用

输入命令:

g++ -E test.cpp -o test.i

注意:g++是C++的编译器,当然gcc连Java都可以编译(man文档里有),C++也是没问题的

-E表示只进行预处理,-o将结果存在test.i上

接下来,我们就可以输入

cat test.i

查看结果如下:

void change(int &a, int &b){
 b = a+b;
 a = b-a;
 b = b-a;
 return;
}

我们会发现,注释没有了。这是因为预处理的时候给删了。而且,缩进也变成了一格

但是,引用的特征符号&并没有消失,那么就可以排除这种可能

这说明了引用是在编译的时候起作用的?

首先我们来看我们是怎么定义a的,int &a。像不像int *a?(int *)是a的类型,类比一下,(int &)是不是也是a的类型?

有哪些跟数据类型相关的?typedef给数据类型起别名,指针定义中*前面的类型规定了访问变量存的地址的方式

首先我们来看typedef

将change改成如下代码:

typedef int &qu;

// 交换a和b的值
void change(qu a, qu b){ // &是引用,&a表示a是一个别名
        b = a+b; // 现在a不变,b是a b的和
        a = b-a; // 现在a是b-原来的a,b是a+b,所以现在的a是传进来的b
        b = b-a; // 现在b是b-a,b是a+b,a是原来的b,所以b-a是原来的a
        return;
}

并且通过代码调用这个函数:

change(a, b);

编译一下,竟然没报错!我们运行一下,竟然真的改过来了(当然需要自行加上输出前后的值)

我们暂时得出结论,引用是数据类型!

那么,我们再来看指针

首先我们知道,int *a定义了一个变量(不是定义指针哈),这个变量存着地址,因为前面有个*,int就规定了访问这块地址的方式

如果我们写int &(*a)呢?访问这块地址的方式就变成了(int &)的访问规则。我们试一下

#include <stdio.h>

int main(void){
        int &(*a); // 定义指针类型的变量a
        int &b;    // 定义引用类型的b
        int c = 1; // 定义并初始化普普通通的c
        b = c;     // 让b是c的别名
        a = &b;    // 让a存b的地址
        // 输出c的值,a存的地址里存着b,所以*a就获取到了b本身,即c的别名
        printf("%d\n", *a);
        return 0;
}

不过这段代码可就报错了:

error: cannot declare pointer to ‘int&’
error: ‘b’ declared as reference but not initialized

第一条错误信息的意思是:不能声明一个指向int &的指针,啥意思,就是不能创建“指向”引用类型的变量

第二条错误信息的意思是:'b'被声明为引用但没有初始化。这说明,引用类型的变量必须要初始化

那么我们可以初步得出结论:引用是数据类型!因为&读作引用

引用是怎么在地址空间里存储的

我们前面发现,指针变量里存的地址,是不能用引用的方法访问的。难道我们就没有办法研究这个了吗?

不管怎样,先sizeof了再说

#include <stdio.h>

int main(void){
        printf("sizeof(char)=%d\n", sizeof(char));
        printf("sizeof(char &)=%d\n", sizeof(char &));
        printf("sizeof(int)=%d\n", sizeof(int));
        printf("sizeof(int &)=%d\n", sizeof(int &));
        return 0;
}

编译运行,结果是:

sizeof(char)=1
sizeof(char &)=1
sizeof(int)=4
sizeof(int &)=4

没错,sizeof(char &) = sizeof(char);sizeof(int &) = sizeof(int)

接下来我们肯定要对引用类型的变量取地址了

int a;
int &b = a;
printf("&a = %p\n", &a);
printf("&b = %p\n", &b);

输出结果是

&a = 0xbff7904c
&b = 0xbff7904c

这说明,引用类型的变量的地址与初始化时“赋值”的变量一致。这也就是引用的原理

但是严格来说,引用类型的变量其实并不完全是变量。因为它必须在初始化的时候“赋值”。C语言里完全可以int *p; p = (int *)0;。如果说int &a里a是变量的话,它又不能随意赋值。在C++的拓展中,引用可以算是特殊的一员,但绝不是唯一的

使用引用

研究到这里我们可以如此使用引用:

int &a = var;

其中,int是a这个引用变量(引用类型的变量)的访问规则。即:当访问a时,遵循int的访问规则

我们可以写如下代码以证明:

int var = 1000; // 定义var并初始化为1000
int &b = var;   // 定义引用变量b并初始化为var,但b是(int &)类型的
char &c = (char &)b; // 定义引用变量c并初始化为(char &)b,但c是(char &)类型的
printf("%d\n", c);

?结果输出-24

这说明,“&”前面的数据类型规定了访问规则

&说明了变量是引用类型,没什么可说的。

a是变量本身,但要注意,引用必须初始化

引用的一些其它事项

研究到这里,我们发现,引用变量是,但不完全是变量的别名,而引用本身是数据类型。

引用变量不是变量的别名?

我们来看前面的这段代码:

int var = 1000; // 定义var并初始化为1000
int &b = var;   // 定义引用变量b并初始化为var,但b是(int &)类型的
char &c = (char &)b; // 定义引用变量c并初始化为(char &)b,但c是(char &)类型的
printf("%d\n", c);

其中,b和c都是引用变量,b姑且可以算是var的别名,但c是什么?c不是var的别名,因为访问方式都不一样。

在一般情况下,引用可以看成是变量的别名,但实际上,引用并不是变量的别名引用只不过是与某个变量地址一样的另一个变量罢了,甚至访问方式都可以不一样。

引用类型跟指针类型的区别

我们知道,引用类型的变量的内容是某个变量的内容(所以它必须初始化),且它的地址与这个变量相同。而指针类型的变量的内容是地址(不一定非得是某个变量的,所以不需要初始化),且它的地址不一定是它存的这块地址。

我们会发现,引用变量是靠着自己的地址与别的变量的地址相同对这个变量进行操作的,而指针变量也可以赋值为这片地址,所以,引用能实现的指针也行,但是更简单。所以我们说,引用是指针的拓展

关于我用stdio.h写C++这件事

我用标准库写C++有问题吗?没有问题

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 10:25:04  更:2022-08-06 10:26:16 
 
开发: 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年5日历 -2024/5/9 19:16:10-

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