引用类型的定义是什么?

10

如何以正式严谨的方式定义(解释)C ++中的引用类型?

我尝试过在Google上搜索,并查看了Stroustrup的《C ++编程语言》,但我没有在那里看到这个概念的定义。


2
你可以在这里找到一个很好的解释:std::is_reference - πάντα ῥεῖ
2
正式定义在[dcl.ref],C ++11 8.3.2 中。这太长而且晦涩难懂,无法在此贴出。任何不错的入门书都应该给您提供良好的非正式描述。 - Mike Seymour
@πάντα ῥεῖ:我在你提供的链接中并没有看到任何解释。 - AnT stands with Russia
如果T是引用类型(左值引用或右值引用)@AndreyT - πάντα ῥεῖ
@πάνταῥεῖ:这并没有解释什么是引用,只是is_reference可以告诉你任何给定类型是否为引用。 - Mike Seymour
显示剩余4条评论
4个回答

9
一个引用是一个别名,一个对象的替代名称。它本身不是一个对象(因此不是指针),即使它们的一些用法与指针的用法重叠,也不能算作一个对象。
由于引用不是对象,它们在处理时具有某些限制。例如,你不能创建一个引用数组。它们必须在声明时初始化(绑定、座位),因为它们无法没有对象作为别名而存在。
但是你可以存储它们,并且它们遵循自动变量或成员变量的规则。其中一种用途是通过 C++ 的传值函数调用来访问。
请注意,const 引用有一个很好的副作用:当绑定到临时(即未命名)对象时,它们会给该对象一个名称,从而将其生命周期延长到引用本身的生命周期。
{ // Block scope
     Foo fooVal = makeFoo(); // Say makeFoo() returns a (temporary, unnamed) Foo
     // Here the temporary Foo is dead (fooVal is a copy).

     // Foo &fooRef = makeFoo(); // Error, reference is non-const
     Foo const &fooCRef = makeFoo(); // All good

     // ...

     // The second temporary is still alive
     fooCRef.doSomethingFunny(); // Works like a charm !

} // The second temporary dies with fooRef

请注意,有时可能会出现对象超出其作用域,但仍有引用指向它的情况。这时将会产生悬空引用,不再使用它们(这样做将导致未定义的行为)。

Foo *fooPtr = new Foo; // Here is a Foo
Foo &fooRef = *fooPtr; // Here is an alias for that Foo

delete fooPtr; // Here is the end of that Foo's life

fooRef.doSomethingFunny(); // Here comes trouble...

3
关于C++引用类型的定义,C++11标准在其§8.3.2/1中给出了如下正式严格的定义:
在声明T D时,D具有以下形式之一: & attribute-specifier-seqopt D1 && attribute-specifier-seqopt D1 并且声明中标识符的类型为“derived-declarator-type-list T”,则标识符D的类型为“derived-declarator-type-list引用类型T。”
然而,如果你更关心C++引用的实际含义(除了口语化使用外),请查看表达式中其含义的定义,在其§5.5中给出了如下解释:
如果一个表达式最初的类型是“引用类型T”(8.3.2,8.5.3),则在进一步分析之前将其调整为类型T。该表达式指定由引用表示的对象或函数,并且根据表达式将其作为左值或右值。
这意味着引用作为一个别名。可以把引用看作是一个自动解引用的const指针,这解释了大部分行为,但引用不一定占用存储空间(编译器可能会将其完全优化掉)。

2
根据一些专家的观点,引用类型并不是C++引用本身,而是与值类型相对应。我提出了两个略有不同的定义——值类型和引用类型。

https://abseil.io/blog/20180531-regular-types

这是Titus Winters的一篇博客文章,他是C++子委员会负责C++标准库的主席。

据Titus Winters称,值类型和引用类型的区别在于复制行为。当您复制值类型的实例时,您得到两个独立的对象,它们一开始是相等的,但在其中一个修改后可能会有所不同。当您复制引用类型时,您得到两个对象,它们引用相同的数据。

引用类型不拥有它们的数据。一些引用类型允许修改所引用的数据(例如span),而一些不允许(例如string_view)。这两个示例都非常适用于函数参数传递。函数调用者通过惯例保证了引用类型的基础数据在函数调用期间不会被销毁(就像普通的C++引用一样)。

https://learn.microsoft.com/en-us/cpp/cpp/value-types-modern-cpp?view=vs-2019

微软文档将引用类型视为多态类型(具有至少一个虚函数或成员变量的类型),而将值类型视为非多态类型。(Bjarne Stroustrup 将非多态类型称为具体类型。)
值类型涉及内存和布局控制,引用类型涉及身份。
值类型允许编译器直接访问成员,引用类型需要间接访问由于运行时多态性。
微软认为引用类型是不可复制的(以防止切片)。
因此,语义不同,Titus Winters 通过实际复制行为定义引用类型。

0
C和C++之间的一个重要区别(除了对象和类!)是引用。 引用就像是一个指向变量的const指针。 给一个引用赋值有点像使用指针,但是使用的符号是&而不是*,并且你不需要进行区分。 不同之处在于你给一个指针分配一个地址,而给一个引用变量分配一个变量。 以下代码行表明a的值被复制到aref中。 但实际上没有复制,相反aref是变量a的引用。 一旦分配,aref就与a相同。 对aref的任何更改都会更改a,正如下面的示例所示:

int & aref = a;

 #include <stdio.h>
 #include "stdafx.h"

  int main()
   {
      int a=9;
      int & aref = a;
      a++;
      cout << "The value of a is %i\n" << aref;
      return 0;
    }

还要记住:

  1. 引用必须始终指向某个对象,不允许为空。

  2. 在创建引用时必须初始化,未初始化的引用是不存在的。

  3. 一旦初始化后,引用就不能被改变指向其他变量。

如果有帮助请告诉我,谢谢。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接