70

这些是否相同:

int foo(bar* p) {
  return p->someInt();
}

int foo(bar& r) {
  return r.someInt();
}

忽略空指针电位。这两个函数在功能上是否相同,无论someInt()是 virtual 还是传递了bar的子类或子类bar

这切任何东西:

bar& ref = *ptr_to_bar;
4

8 回答 8

74

C++ 引用故意没有在标准中指定使用指针来实现。引用更像是变量的“同义词”,而不是指向它的指针。这种语义为编译器打开了一些可能的优化,当它可能意识到在某些情况下指针可能是一种过度杀伤力时。

还有一些区别:

  • 您不能将 NULL 分配给引用。这是一个至关重要的区别,也是您更喜欢其中一个的主要原因。
  • 当您获取指针的地址时,您将获得指针变量的地址。当您获取引用的地址时,您将获得被引用变量的地址。
  • 您不能重新分配参考。一旦它被初始化,它的整个生命周期都指向同一个对象。
于 2009-03-06T22:12:36.227 回答
15

忽略每个语法糖和可以用一个而不是另一个来完成的可能性,以及在其他答案(其他问题)中解释的指针和引用之间的区别......是的,这两个在功能上完全相同!两者都调用函数并且都同样处理虚函数。

不,你的线没有切片。它只是将引用直接绑定到指针指向的对象。

关于为什么要使用其中一个的一些问题:

我没有尝试自己提出差异,而是将您委托给那些您想知道的人。

于 2009-03-06T22:33:27.427 回答
13

引用是一个常量指针,即您不能更改引用以引用其他对象。如果您更改,引用对象的值会更改。

例如:

       int j = 10;
       int &i = j;
       int l = 20;
       i = l; // Now value of j = 20

       int *k = &j;
       k = &l;   // Value of j is still 10
于 2009-03-07T05:30:41.430 回答
7

是的,它们在功能上是相同的。由于引用将要求您在使用它之前将其设置为对象,因此您不必处理空指针或指向无效内存的指针。

查看语义差异也很重要:

  • 当您实际上将正常传递对象时使用引用 - 但它是如此之大以至于传递对对象的引用而不是制作副本更有意义(如果您不修改对象)。
  • 当您想处理内存地址而不是对象时,请使用指针。
于 2009-03-06T22:14:12.697 回答
5

我很久没有使用 C++,所以我什至不会尝试真正回答你的问题(对不起);然而,Eric Lippert 刚刚发布了一篇关于指针/引用的优秀文章,我想我会指给你看。

于 2009-03-06T22:11:42.440 回答
4

不确定是否有人回答了隐藏在底部的关于切片的第二个问题......不,这不会导致切片。

切片是指派生对象被分配(复制)给基类对象——派生类的特化被“切片”掉。请注意,我说的是对象被复制,我们不是在谈论被复制/分配的指针,而是对象本身。

在您的示例中,这没有发生。您只是取消引用指向 Bar 对象的指针(从而导致 Bar 对象)在引用初始化中用作右值。不确定我的术语是否正确...

于 2009-03-07T02:40:29.670 回答
3

正如其他人所提到的,在实现中引用和指针在很大程度上是相同的。有一些小警告:

  • 您不能将 NULL 分配给引用(shoosh 提到了这一点):这很重要,因为没有“未定义”或“无效”的引用值。

  • 您可以将临时变量作为const引用传递,但将指针传递给临时变量是不合法的。

例如,这没关系:

class Thingy; // assume a constructor Thingy(int,int)
void foo(const Thingy &a)
{ 
   a.DoSomething();
}

void bar( ) 
{
  foo( Thingy(1,2) );
}

但大多数编译器都会抱怨

void foo2( Thingy * a);

void bar2()
{
  foo( &Thingy(1,2) );
}
  • 获取变量的地址以获取指针会强制编译器将其保存到内存中。分配对局部变量的引用只会创建同义词;在某些情况下,这可能允许编译器将数据保留在寄存器上并避免load-hit-store。但是,这仅适用于局部变量——一旦通过引用将某些内容作为参数传递,就无法避免将其保存到堆栈中。

 

void foo()
{
   int a = 5;
   // this may be slightly more efficient
   int &b = a;
   printf( "%d", ++b );
   // than this
   int *c = &a;
   printf( "%d", ++(*c) );
}
  • 同样,__restrict 关键字不能应用于引用,只能应用于指针。

  • 你不能对引用进行指针运算,所以如果你有一个指向数组的指针,那么数组中的下一个元素可以通过 p+1 获得,一个引用在其整个生命周期中只指向一个事物。

于 2009-03-06T22:46:16.473 回答
1

这些功能显然不是“相同的”,但就虚拟行为而言,它们的行为相似。关于切片,这只发生在处理值时,而不是引用或指针。

于 2009-03-06T22:16:39.977 回答