采用以下示例。我创建了一个名为s
的函数指针,将其设置为f
并调用它。这当然很好:
void f() {}
int main() {
void (*s)();
s = f;
s();
}
但是接下来的例子,我现在将s
声明为“函数引用”(如果它被称为)并设置为f
内联。编译也很好:
void f() {}
int main() {
void (&s)() = f;
s();
}
创建和初始化函数指针的这两种方法有什么区别?请注意,当我使用引用语法时,我需要将其“内联”初始化为f
,而使用“指针”语法,我有能力以两种方式执行此操作。你能解释一下吗?有了这个,你能解释一下他们在可用性方面的差异,我何时必须使用一种形式而不是另一种形式?
答案 0 :(得分:3)
从根本上说,主叫方没有明显的区别。但 decl 方面确实如此。正如您所指出的,必须初始化引用以引用某些内容。这使他们“更安全”,但即便如此也无法保证“安全”。
函数指针根本不需要指向函数。它可能是NULL,甚至是未初始化的(指向垃圾)。并不重要,因为你以后总是可以改变它(你不能用引用做的事情)。
void (*s)(); // uninitialized
或
void (*s)() = NULL; // set to null
以后
void foo()
{
}
s = foo;
你不能做任何带参考的人。引用必须初始化为某些,并且首选有效:
void (&f)() = foo; // ok. also references foo().
void (&f)() = *s; // also ok, but wait, is s valid?? does it have to be??
然而,即使在这里,功能参考也不保证是安全的,只是更安全。你当然可以这样做:
void (*s)();
void (&f)() = *s;
您可能会收到编译器警告(我这样做,“在初始化之前使用”)但最后f
仍然是对不是“功能”的引用一个功能;只是s
指针中的随机堆栈垃圾。更糟糕的是,因为引用无法重新分配。这件事总是指向垃圾。
答案 1 :(得分:2)
差异与任何指针/引用相同。
必须初始化引用,以后不能重新分配:
int i,j;
int &r = i;
r = j; // i = j, not &r == &j
引用不能被视为与它们引用的对象不同的对象(而不是指针,它们是与它们指向的对象不同的对象)...
int i;
int *p = &i; // &p != &i
int &r = i; // &r == &i
使用函数指针在语法上看起来与使用引用相同,但这是因为带有函数指针的特殊规则允许您在不解除引用的情况下使用它们。
答案 2 :(得分:2)
你自己说过,不同之处在于,使用引用时,必须在声明时将其绑定,这样可以保证引用始终引用有效对象。 另一个不同之处在于引用在声明之后不能被重新引导,因此它们在一生中只引用一个对象。
除此之外,他们是一回事。 我遇到了一些喜欢引用的纯粹主义者,并说指针是不应该使用的C的痕迹。 其他人更喜欢指针,因为他们更明确地指出它们是指针。
是否使用其中一种取决于您的需求。选择的方法是,如果可能的话使用引用,但是如果你真的需要能够将它指向不同的函数,那么使用指针。
答案 3 :(得分:0)
对类型P的引用很像类型P的const指针(不是指向const P的指针,它是不同的)。
如果您的P类型是函数类型,它们的大多数不同方式并不重要。 &安培;行为略有不同,你可以直接将指针指向非const指针,而带有一个指针的函数可能不会占用另一个指针。
如果类型P不是函数类型,则会出现其他差异 - operator =,临时生命等等。
简而言之,答案是“不多”。
答案 4 :(得分:0)
函数标识符是函数类型的表达式,但它们隐式转换为指向函数类型或函数类型。因此,它们可以传递给引用或指针的构造函数以及指针的operator =。
由于引用的语法行为与实例相似,因此无法对引用而不是引用的对象进行操作。这就是他们只能初始化的原因。顺便说一句,C ++中首选的语法是括号,而不是=
。
只有在不能使用引用时才应使用引用和指针。原因是,由于许多事情无法进行引用(指向NULL,更改引用对象,删除它等),因此在阅读代码时需要查找的内容较少。此外,它还可以节省一些*
和&
字符。