C++的数组元素为什么不能是引用类型
来源:互联网 发布:无线传感器网络三要素 编辑:程序博客网 时间:2024/05/22 08:22
感谢原作者分享:http://blog.xinspace.space/2015/01/25/cpp-array-element-not-ref/
这几天在看c++基础内容,看到数组的时候,书里提到数组元素的约束条件:
1.元素类型支持赋值操作。
2.元素类型支持复制。
因此,除了引用类型对象和流对象外,其他的任意内置类型和满足上述约束的类类型均能成为数组的元素。
流对象不能成为数组元素是因为它不支持复制和赋值,不满足上述的两条约束。而引用却是可以赋值和复制呀,为什么数组元素不能是引用呢?
先讲一下引用的某些特点:
1.引用是对象的另一个名字(这里的对象指内存的区域,如int所占内存4个字节)。定义一个对象的引用,该引用并不占内存空间,它只是这个对象的别名。
举个例子:
int i = 10;该语句定义变量i为整型,占用4字节内存空间,初始值是10。粗略的说,这条语句在执行时操作系统从内存中分配4字节(假如地址是0x00000000-0x00000003),将这4个字节贴一个标签,叫i(若没有标签,想要读写这4字节就只能使用二进制或十六进制的地址了,比较麻烦)。之后,若程序读写i,就代表着读写这4个字节。所以i就是这4字节对象(这个对象指内存的特定区域,并不是面向对象中的对象)的一个名字或标签。对i赋值,就会把值写入到这4个字节的对象中。通过i可以方便的访问内存中的对象。i本身不占用内存空间,i代表的对象占用4字节空间。
int &ir = i;该语句定义引用ir,将其绑定到i所代表的对象。所以,ir就像i一样是一个名字、标号,ir代表的对象与i一样而已,就是0x00000000-0x00000003这4个字节。
那么定义一个变量和定义一个引用有什么区别吗?可以这么理解,定义变量时操作系统帮我们分配的内存空间(对象)、把变量名作为该对象的标签绑定到该对象上。而定义引用时操作系统只帮我们产生了一个标签,但是不会产生对象,当然也不会将这个标签绑定到某个对象上。因此,将引用这个标签绑定到对象上的工作需要程序员来做。
2.引用必须绑定到相应的对象。引用在定义时必须初始化,绑定到相应的对象,且之后不能更改。
从第1个特点来看,程序员必须手动将引用绑定到某个对象上。这就要求在定义引用时就必须给他提供初始化式,这个初始化式代表了某个对象(即内存中的某片区域)。如果程序员不这么做,那么这个标签的存在就没有意义,毕竟不能读写一个标签(即不能读写标签所代表的内存空间)在程序中没有任何意义,因此编译时便会报错。
而且引用在绑定到一个对象之后,不能够再改变。这很好理解:如果标签Q能够绑定到不同的对象的话,那么程序中不同位置出现的Q到底代表了哪个对象?是0x00000000-0x00000003(4字节,如int型)还是0x00000011-0x00000018(8字节,如double型)?因此,只要这个对象生命周期还未结束(在同一个作用域中),这个标签就一直贴在它身上,不能再用于其他对象。当然,不同的作用域可以出现重复的标签,这另当别论。
再说一下为什么数组的元素不能为引用:
1.大数组初始化麻烦。引用在定义时必须初始化。若数组元素是引用的话,则必须对每个元素进行初始化。比如int a[100000000]这样的大数组,一一赋值很麻烦。就算你可以一一初始化每个元素,那么往下看。
2.破坏数组元素的内存存放连续性。数组的一大优点就是可以随机快速访问某个元素,这是因为数组不仅在逻辑上连续,在物理上也连续。如对数组int a[10],给其第4个元素赋值可以写为:*(a+3) = 15;。能这么写是因为数组元素在内存中是连续存放的,如果数组a的首地址为0x00000000,那么a[0]的地址是0x00000000,a[1]的地址是0x00000004,a[2]的是0x00000008,以此类推。a中每个元素都占用4个字节空间,每个元素在逻辑上是连续的,即第2个元素紧接着第1个元素;同样,数组在物理内存中的存放也是连续的,即第2个元素的地址紧挨着第1个元素。
那么,数组元素为引用会是什么情况?上面引用第1个特点中提到,引用只是标签,需要手动绑定到某个对象(地址区域)才行。那么在给数组中的引用初始化时,不能保证逻辑上连续的引用元素所绑定的对象也正好物理上连续。
举个例子:
假如引用数组是合法的,编译可以通过,那么根据语法来说,定义语句应该是这样的:int &a[4],a是一个数组,有4个元素,每个元素都是引用。当然,我们还需要对每个元素进行初始化,所以写全的话是这样:
//首先定义4个对象,内存地址、标签和初值如下:
int i1 = 10; //内存地址是0x00000000-0x00000003,初值是10
int i2 = 11;//内存地址是0x00000014-0x00000017,初值是11
int i3 = 12;//内存地址是0x0000000c-0x0000000f,初值是12
int i4 = 13;//内存地址是0x00000020-0x00000023,初值是13
int &a[4] = {i1, i2, i3, i4};//a的4个元素分别绑定到4个对象。
这样看来,既然a是数组,那么逻辑上第1个元素紧挨着第2个元素,物理上也应该如此。但是这个例子告诉我们,a数组的元素在物理上并不连续,a[0]的地址是i1的地址,a[1]的地址是i2的地址,以此类推。甚至a[2]的地址比a[1]的地址还要靠前(本应该靠后才对)。
正是由于引用只是别名,不占用内存空间,才导致了上述的这个问题,使得数组在物理上不连续了。这样的话类似*(a+3)=15;的语句就行不通了。因为a+3是这样计算的:a的地址+3×元素所占字节数。这么计算的根基就是必须保证物理连续,否则无法通过数组首地址推出其余元素的地址。
3.操作系统无法为引用数组分配空间。对象是要占用内存空间的,如int a[10];这条定义语句定义了一个有10个整型元素的数组,因此操作系统在运行时从内存划出40字节留给数组a,然后访问a就会访问这40字节的地址。但是引用是不占用内存的,它只是名字,所以如果数组元素是引用的话,如int &ar[10]={….};,这个数组到底占用多少内存?不知道!因为引用不占用空间,操作系统无法给数组分配内存空间,也就无法读写这个数组。无法读写的数组还有意义吗?
综上所述,数组的元素不能是引用。
- C++的数组元素为什么不能是引用类型
- 不能建立引用数组,数组中的元素不能是引用
- C为什么要把数组类型的函数参数认为是指向数组第一个元素的指针
- 为什么不能建立引用的数组?
- C#中数组是引用类型
- 泛型类的类型为什么不能是基本
- 为什么不能建立引用数组?
- string 为什么是引用类型
- 你不知道的c语言之为什么数组的大小不能是变量
- C语言:二维数组元素的引用
- 为什么C++类定义中,数据成员不能被指定为自身类型,但可以是指向自身类型的指针或引用?
- 为什么C++类定义中,数据成员不能被指定为自身类型,但可以是指向自身类型的指针或引用?
- 为什么能数组引用,但不能引用数组
- 【c++】为什么类的定义中不能包含其自身类型,但是能包含其自身的指针或引用类型
- 为什么类的定义中不能包含自身类型,而可以包含其自身的指针类型和引用类型
- PHP数组是否是引用类型?
- C++拷贝构造函数 参数类型为什么是引用类型 ...
- matlab数组元素的引用
- Spring IOC
- cadence学习问题记录
- 1108. Finding Average (20)
- Catch That Cow
- 获取文件夹下所有文件和文件夹(递归)
- C++的数组元素为什么不能是引用类型
- MAVEN_依赖管理
- 让Win32窗口程序拥有控制台窗口
- 一条 sql group by
- PL/SQL结构
- [USACO3.3.5]A Game
- getLocationInWindow()与getLocationOnScreen()
- NIOP2015Day2T1 跳石头解题报告
- 第七章 函数表达式(闭包重点)