引用 (程序设计)

电脑科学中,引用(英语:reference)是指一个可以让程序间接存取于电脑存储器或其他存储装置中一特定资料的,该数据可以为变量记录

引用和资料本身不同。一般而言,引用会是资料存储于存储器或存储装置中的物理地址。因此,引用亦常被称为该资料的指针地址。不过,引用也被用来指资料地址和某一固定“基准”地址的偏移值,或是数组的索引。

引用的概念和其他如关系键识别字之类用来识别特定资料项目的值不同,后者只能透过数据库表中的查找运算,来存取资料。

引用被广泛用于程式设计之中,尤其是用于将大量或易变的资料有效地透过参数传给子程序,或在不同的用途中共享此类资料。此外,引用也能指向一个包含其他资料之引用的变量或记录,此一概念为间接寻址链接数据结构(如链接串列)之基础。

例子

指针是最简单的引用,由于和底层硬件的亲密关系,使其成为最强大及有效的引用之一。不过,也因为此一关系,程序员在使用指针时,必须非常了解存储器架构的细节。因为指针存储存储器的地址,而非直接存储值,不正常地使用指针会导致程序出现未定义行为智慧指针是一个非透明指针,作用和指针相似,但只能透过特定方式存取。

句柄是一种抽象引用,可用许多不同方法呈现。其中一个常见的例子为文件句柄(用于C语言标准输入/输出函数库中的文件数据结构 ),用来描述抽象的文件内容。文件句柄通常可用来表示文件本身(当要求该文件的时),以及文件内容中的某一特定位置(当读存该文件时)。

分布式计算中,引用可能包含一个以上的地址或识别字;也可能包括用来定位或存取引用物件之网络协议的编码格式,用来说明消息被编码或序列化之方式。举例来说,WSDL中对远程网络服务的描述可被视为一种引用,包括如何定位及绑定特定Web服务之完整格式。另一个例子为对即使分布式物件的引用:该引用为一个如何建设称之为“代理(proxy)”之小型软件组件的完整格式,此代理接着会执行点对点(peer-to-peer)的交互,并使本地机器得以存取被复装或只存在部分一致之消息流的资料。

编程语言的支持性

在第一个被使用的编程语言-汇编语言中,一般使用未处理的存储器地址或数组中的索引表示引用。这样使用是可行的,但有点微妙,因为一个地址无法告诉你它指向的值是什么,更不用说这个值有多大,或是该如何解释;此类消息都内含在程序的逻辑之中。如此一来,误解将可能出现在不正确的程序里,引发令人感到困惑的错误。

最早的不透明引用为LISPCONS函数,此一函数只是一个包含两个引用至其他Lisp物件的记录,其他Lisp物件也可能包括其他的cons函数。此一简单的结构最常被用来建构单向链接串列,但也可用来建构简单的二叉树,以及一种被称为“点状串列”的结构,该结构最终会终止于一个值上,而非空引用。

另一个早期的语言-Fortran则没有明确用来表示引用的用法,但可以传引用调用的方式使用引用。

指针依然是今日最常见的一种引用,类似于汇编语言中对未处理存储器地址的表示方式,不同之处在于指针带有一个固定之资料类型,可在编译期间用来确保所指之资料不被误解。不过,因为C语言有个可以使用类型转换(在不同指针类型间及指针类型与整数间转换)的弱类型系统,虽然较为困难,但还是有可能误解。C++试图在C++标准程序库中使用新的cast运算符及较聪明的指针,以增加类型安全;但为了兼容性,仍保留绕过这些安全机制的能力。

许多今日常见的主流语言,如EiffelJavaC#Visual Basic等,则均采用了一种更加不透明的引用,通常即简称为“引用”。此类引用具有类似C语言指针的类型,会指出其所引用资料的意思;不过,此类引用为类型安全的,无法指向一个未处理的地址,以及进行不被允许的不安全转换。

引用与指针的区别

对于同时支持引用与指针的C/C++,两类数据型的区别有:

  • 指针可以重新赋值,而引用在初始化绑定后就不能再绑定到其他对象。
  • 指针对象有它自己的内存地址与内存长度,而引用与它指向的对象具有相同的内存地址、内存长度。因此,可以把引用看作是被指向对象的另一个名字。
  • 指针可以指向另一指针,因此允许多层的指针间址(indirection);而引用只允许到对象的一层间址,不允许“引用的引用”。
  • 指针可以直接赋值为NULL,引用不能。当然,可以费劲办法把引用绑定到内存的NULL上,但这并不实用。
  • 指针可以在数组上遍历(iterate),引用不能。
  • 指针需要用运算符“*”来解引用(dereference)以访问它所指向的内存的内容;引用不需要显式解引用。指向类/结构的指针访问成员变量/成员函数需要用运算符->而引用使用运算符.来访问成员。
  • 指针是一个变量,保存了内存地址;而C++标准都没有明说引用是如何实现的。实际上,几乎所有C++编译器把引用作为一个隐式的指针来实现。
  • 指针可以成为数组的成员类型,即指针数组;但引用不可以作为数组的成员类型,即不存在“引用数组”。
  • const引用可以绑定到临时对象;而指针不能(例如,int *y = 12;编译出错)。按照C++11语法,const左值引用可以绑定到一切对象,包括const左值对象,非const左值对象,const临时对象,非const临时对象;右值引用当然可以绑定到临时对象。

参考文献

参见