这两者是否相同:
int foo(bar* p) {
return p->someInt();
}
和
int foo(bar& r) {
return r.someInt();
}
忽略空指针的可能性。无论someInt()
是否是虚函数,以及它们是否传递了bar
或bar
的子类,这两个函数在功能上是否相同?
这会切割什么:
bar& ref = *ptr_to_bar;
这两者是否相同:
int foo(bar* p) {
return p->someInt();
}
和
int foo(bar& r) {
return r.someInt();
}
忽略空指针的可能性。无论someInt()
是否是虚函数,以及它们是否传递了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
你不能将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 来获取数组中的下一个元素,但是引用在其整个生命周期中只会指向一个东西。
这些函数显然不是“相同的”,但就虚拟行为而言,它们的行为类似。关于切片,这仅在处理值时发生,而不是引用或指针。