这些是否相同:
int foo(bar* p) {
return p->someInt();
}
和
int foo(bar& r) {
return r.someInt();
}
忽略空指针电位。这两个函数在功能上是否相同,无论someInt()
是 virtual 还是传递了bar
的子类或子类bar
?
这切任何东西:
bar& ref = *ptr_to_bar;
这些是否相同:
int foo(bar* p) {
return p->someInt();
}
和
int foo(bar& r) {
return r.someInt();
}
忽略空指针电位。这两个函数在功能上是否相同,无论someInt()
是 virtual 还是传递了bar
的子类或子类bar
?
这切任何东西:
bar& ref = *ptr_to_bar;
C++ 引用故意没有在标准中指定使用指针来实现。引用更像是变量的“同义词”,而不是指向它的指针。这种语义为编译器打开了一些可能的优化,当它可能意识到在某些情况下指针可能是一种过度杀伤力时。
还有一些区别:
忽略每个语法糖和可以用一个而不是另一个来完成的可能性,以及在其他答案(其他问题)中解释的指针和引用之间的区别......是的,这两个在功能上完全相同!两者都调用函数并且都同样处理虚函数。
不,你的线没有切片。它只是将引用直接绑定到指针指向的对象。
关于为什么要使用其中一个的一些问题:
我没有尝试自己提出差异,而是将您委托给那些您想知道的人。
引用是一个常量指针,即您不能更改引用以引用其他对象。如果您更改,引用对象的值会更改。
例如:
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
是的,它们在功能上是相同的。由于引用将要求您在使用它之前将其设置为对象,因此您不必处理空指针或指向无效内存的指针。
查看语义差异也很重要:
我很久没有使用 C++,所以我什至不会尝试真正回答你的问题(对不起);然而,Eric Lippert 刚刚发布了一篇关于指针/引用的优秀文章,我想我会指给你看。
不确定是否有人回答了隐藏在底部的关于切片的第二个问题......不,这不会导致切片。
切片是指派生对象被分配(复制)给基类对象——派生类的特化被“切片”掉。请注意,我说的是对象被复制,我们不是在谈论被复制/分配的指针,而是对象本身。
在您的示例中,这没有发生。您只是取消引用指向 Bar 对象的指针(从而导致 Bar 对象)在引用初始化中用作右值。不确定我的术语是否正确...
正如其他人所提到的,在实现中引用和指针在很大程度上是相同的。有一些小警告:
您不能将 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) );
}
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 获得,一个引用在其整个生命周期中只指向一个事物。
这些功能显然不是“相同的”,但就虚拟行为而言,它们的行为相似。关于切片,这只发生在处理值时,而不是引用或指针。