什么是 C 语言中的引用?

What is a reference in C?

提问人:Flash 提问时间:8/17/2010 最后编辑:einpoklumFlash 更新时间:7/4/2022 访问量:1040

问:

我刚刚开始使用 C++,遇到了参考文献,还没有完全理解。

正如我所读到的,引用是对象的替代名称。为什么使用它而不是直接访问对象,因为对引用的任何操作都会直接反映在对象上......?

  1. 为什么以及何时使用它们?
  2. ist 是否像一个常量指针,每次使用时都会被引用......?

而且,它说

 double& dr = 1;  ----  says it is an error (some lavalue needed) 
 const double& cdr = 1;  ---- says it is ok. 

我没有正确理解它..所以请解释一下为什么会这样......

谢谢...:)

C 参考手册 C++-FAQ

评论

0赞 8/17/2010
C++ 中指针变量和引用变量之间的差异的可能重复
0赞 Bob Fincheimer 8/17/2010
如果你想知道为什么这两行有效/不起作用,看看我的回答

答:

3赞 bradgonesurfing 8/17/2010 #1

引用基本上是一个看起来像对象的指针。获得 NULL 引用非常非常困难,尽管您可以浏览箍并创建一个。

关于您的示例,1 是右值或结果。它只是一个临时变量,无法修改。因此,你不能对它进行非常量引用。但是,您可以对它进行常量引用。这意味着您无法更改引用的值。

下面是创建 NULL 引用的示例。别这样!

int * x = (int *)NULL;
int & y = *x;

评论

2赞 fredoverflow 8/17/2010
如果不调用未定义的行为,就不可能获得“空引用”。
0赞 bradgonesurfing 8/18/2010
并非不可能,如果您可能访问它,您将获得一个 seg-v。
0赞 Tyler McHenry 8/18/2010
如果不调用未定义的行为,这是不可能的。在您的示例中,有一个 NULL 取消引用,即 UB。*x
0赞 MSalters 8/18/2010
是的,有些编译器可以精确地进行优化,因为你不能有 NULL 引用。因此,他们甚至可能懒得执行您的第二条语句。
0赞 bradgonesurfing 8/18/2010
我认为我的观点是这是可能的,这是编码人员应该注意的事情。您可能会在意想不到的位置看到段式 v,而不是在创建引用时看到段式 v。是的,这是未定义的行为,但我已经看到很多代码通过访问器方法将成员指针转换为常量引用,并且值得了解当您的代码出错时您可能拥有什么。
0赞 Cedric H. 8/17/2010 #2
double& dr = 1; // 1.0 would be more clear

无效,因为被视为类型,因此,如果要引用该变量,则需要引用 so1const doubleconst double

const double& dr = 1.0;

是正确的。

3赞 t0mm13b 8/17/2010 #3

引用是最初在 C 代码中出现的另一种方式,如下所示

void fubarSquare(int *x){
  int y = *x;
  *x = y * y;
}

// typical invocation
int z = 2;
fubarSquare(&z);
// now z is 4

使用 C++ 中的引用,它会是这样的

void fubarSquareCpp(int& x){
   x = x * x;
}

// typical invocation
int z = 2;
fubarSquareCpp(z);
// now z is 4

这是一种更简洁的语法方式,它使用按引用调用参数,而不是使用 C 的符号星号/星号来指示指针并作为按引用调用参数......并直接在函数外部修改参数...

请看Bjarne Stoustrap的页面其中介绍了C++是如何的,还有这里的技术常见问题解答

1赞 neuro 8/17/2010 #4

我同意你的看法。仅将引用用作别名不是很有用。 如果将其视为不可变指针,则会更有用。但实际上并没有那么有用。

实际上,它用于定义干净的接口。例如,当您定义:

int foo(const int& param);

你说 param 是 foo 中的只读参数。

不要忘记,您必须为引用赋值。

有关更多信息,请参阅参考中的 C++ faqlite

我的2C

评论

0赞 Stephane Rolland 8/17/2010
我同意。在对象接口级别,它与函数的用户创建了明确的契约。void foo(对象&o){};foo 函数要求指向可修改且不为 NULL 的对象的指针。
11赞 Justin Ardini 8/17/2010 #5

为什么要用它来代替直接 像任何操作一样访问对象 on 参考资料直接反映在 对象...?

C++ 按值传递参数,这意味着如果您有如下函数:

void foo(MyObject o) { ... }

默认情况下,C++ 将复制 ,而不是直接使用传入的对象。因此,引用的一个用途是确保您正在处理同一个对象:MyObject

void foo(MyObject &o) { ...}

或者,如果您不修改:o

void foo(const MyObject &o) { ... }
1赞 Bob Fincheimer 8/17/2010 #6

仔细阅读维基百科文章。总而言之,引用是指针的更友好版本,通常用于将对象作为引用传递到函数中,而不必担心空指针。

解释一下这个例子:


将表示为变量的数字视为一个变量。编译后,该数字被放入内存的全局部分,程序可以引用该部分,但不能修改。1

所以它的类型是:const int

double &dr = 1正在尝试将 (对双精度的引用) 分配给 .由于 is 是一个常量,因此编译器将不允许你对它进行非常量引用。drconst int 11

在第二行中:

const double &dr = 1正在尝试分配(对双精度的常量引用).这之所以有效,是因为引用也是 const,因此可以指向 .drconst int 1const int

编辑在分配之前转换为 a。const intconst double

评论

1赞 jpalecek 8/17/2010
实际上,事实并非如此。文字是 类型的右值,而不是 。您可以在此处看到差异:ideone.com/tzV6p。虽然返回一个 non-const ,但它不能绑定到引用。1intconst intf()A
0赞 Bob Fincheimer 8/17/2010
是的,在这种情况下,文字是右值。但是,当处理全局内存空间中的文字时,它会起作用(参见 ideone.com/aZnid1)
0赞 Dennis Zickefoose 8/18/2010
不,在所有情况下,文字都是 类型的右值。实际值 1 不需要存储在内存中的任何位置,除非您显式创建一个左值来存储它,这是您在链接程序中执行的操作。1int
1赞 Dennis Zickefoose 8/18/2010
在这个具体的例子中,你的解释基本上已经足够好了。它给出了事物背后的直观推理。 显然是一个常量值,所以不应该起作用是有道理的。但在理解参考文献的更广泛概念中,这是一个重要的区别。原因不行就不那么明显了。1int& i = 1;int f(); int& i = f();
1赞 jpalecek 8/18/2010
@Dennis Zickefoose:顺便说一句,语言实际上已经改变了:应该可以工作。int&& i=1
1赞 Stefan 8/17/2010 #7

引用改进了语法,因此不需要指针取消引用。 假设 Base 是一个类,该类可能派生自:

void someFunction(Base b)
{
    b.function();
    // b is a copy of what was passed - probably performance issues
    // possible unintended object slicing - you only get the Base part of it
    // no virtual function call
    // no changes to b visible outside the function
}

void someFunction(Base* b)
{
    b->function();
    // a shortcut for (*b).function();
    // b is the same object that was passed to the function
    // possible virtual call
    // changes visible outside the function
}

void someFunction(Base& b)
{
    b.function();
    // b is the same object that was passed to the function
    // possible virtual call
    // changes visible outside the function
}

引用类似于常量指针(不是指向常量的指针 - 即您可以更改对象,但不能更改为指向的内容)。const reference 是一个引用,通过它你可以执行可以在 const 对象上完成的操作。

引用也很好,因为你不能有空引用

0赞 jszpilewski 8/17/2010 #8

引用的效用在将参数传递给函数的上下文中最为明显。

即,

int a;

func 定义: void foo (int& param) {param = 1;}

函数调用:foo(a);

“param”别名“a”的方式是干净的,它的意图很容易被此代码的读者以及编译器理解,编译器可以在内联引用所需的任何额外内存分配时进行优化。

1赞 jpalecek 8/17/2010 #9

引用是表示它们所引用的另一个对象的语言实体。非常量引用是左值,必须用左值初始化。它们可以像这样有用:

int& x=condition ? array[1] : array[2];
int& y=condition ? array[0] : array[3];
x+=y;
y=0;

当用作函数参数时,它们告诉调用方他必须传递一个可能由函数写入的左值:

void set1(int& x) { x=1; }

int foo;
set1(foo); // ok, foo is 1
set1(foo+1); // not OK, not lvalue

另一方面,Const 引用可以绑定到右值。在函数参数中,它们通常用于避免过多的复制:

void niceness(std::string s); // the string would be copied by its copy-ctor
void niceness(const std::string& s); // the caller's string would be used

请注意,这可能会也可能不会产生更快的代码。

当在普通代码中使用 const-references 时,它们也可以绑定右值,并且作为特殊规则,它们会延长它们绑定到的对象的生存期。这是您在代码中看到的内容:

const double& d=1; // OK, bind a rvalue to a const-ref
double& d=1; // Bad, need lvalue

所有引用都是多态的,就像指针一样:

class A { virtual void f(); }
class B : public A { void f(); }

B b;
A& ar=b;
ar.f(); // calls B::f()

所有引用都是别名,如指针:

int f(int& a, const int& b)
{
  a=1;
  return b;
}

int x;
f(x, 42); // ==42, foo=1
x=42;
f(x, x); // ==1 (not 42), foo=1
0赞 supercat 8/17/2010 #10

传递对函数的引用,然后让函数使用引用,几乎就像将指针传递给函数,然后让函数取消引用指针一样。在许多情况下,机器代码实现是相同的。但是,存在一些差异,尤其是在内联扩展的函数的情况下。如果通过引用将变量传递给内联函数,则编译器在扩展函数时通常能够替换变量本身,即使存储在机器寄存器中也是如此。相反,如果获取变量的地址并将其作为指向函数的指针传递,然后取消引用该函数,则编译器不太可能找出该优化,除非它不仅确定(至少对于函数的一个特定扩展)指针将始终指向该变量,而且还确定指针不会在其他任何地方使用(如果指针在其他地方使用, 变量不能保存在寄存器中)。