在此页面上,我找到了一个很好的C ++函数指针示例(以及函子,但是这个问题与函子无关)。以下是该页面的一些复制内容。
#include <iostream>
double add(double left, double right) {
return left + right;
}
double multiply(double left, double right) {
return left * right;
}
double binary_op(double left, double right, double (*f)(double, double)) {
return (*f)(left, right);
}
int main( ) {
double a = 5.0;
double b = 10.0;
std::cout << "Add: " << binary_op(a, b, add) << std::endl;
std::cout << "Multiply: " << binary_op(a, b, multiply) << std::endl;
return 0;
}
我大致理解了代码,但是有些事情我总是感到困惑。函数binary_op()
接受一个函数指针*f
,但是当使用它时(例如在第19行)binary_op(a, b, add)
,add
传递函数符号,而不是传递给它的指针&add
。现在您可能会说这是因为符号add
是一个指针。它是与功能相对应的代码位的地址add()
。很好,但是这里似乎仍然存在类型差异。该函数binary_op()
采用*f
,这意味着f
它是指向某物的指针。我传入add
,它本身就是代码的指针。(对吗?)然后f
为分配了的值add
,这使得f
指向代码的指针,这意味着该f
函数就像add
,这意味着f
应该调用like f(left, right)
,add
应该如何调用,但是在第12行,它被称为like (*f)(left, right)
,这对我来说似乎不对,因为它就像写作(*add)(left, right)
,而*add
不是功能,它的代码的第一个字符add
点。(对?)
我知道用binary_op()
以下内容替换的原始定义也可以。
double binary_op(double left, double right, double f(double, double)) {
return f(left, right);
}
实际上,这对我来说更有意义,但是如我上面所解释的,原始语法没有意义。
那么,为什么使用语法(*f)
而不是仅仅语法正确f
?如果符号func
本身就是指针,那么“函数指针”或“函数指针”究竟是什么意思?就目前的原始代码而言,当我们编写代码时double (*f)(double, double)
,那是什么一回事f
?指向指针的指针(因为(*f)
本身就是指向一点代码的指针)?该符号是否与add
事物(*f)
相同或相同f
?
现在,如果所有这些的答案是“是的,C ++语法很奇怪,只需记住函数指针语法,不要质疑它”。,那么我会很不情愿地接受它,但是我真的很想对我在这里想的错做一个正确的解释。
我已经阅读了这个问题,我想我理解这一点,但是并没有发现它有助于解决我的困惑。我也阅读了这个问题,它也没有帮助,因为它不能直接解决我的类型差异问题。我可以继续阅读互联网上的信息之海,以找到答案,但是,嘿,这就是Stack Overflow的目的吗?
就目前的原始代码而言,当我们编写代码时
double (*f)(double, double)
,那是什么一回事f
?
的类型为f
,double (*)(double, double)
即它是类型函数的指针double(double,double)
。
因为
(*f)
它本身就是一个指针
它不是。
问:通过指针间接访问(例如in中*f
)会得到什么?答:您会得到一个左值参考。例如,给定的对象的指针int* ptr
,该表达式的类型*ptr
是int&
即左值参考int
。
对于函数指针也是如此:当您通过函数指针间接访问时,您将获得指向所指向函数的左值引用。在情况下*f
,类型是double (&)(double, double)
对类型函数的引用double(double,double)
。
该符号是否与
add
事物(*f)
相同或相同f
?
不合格的id表达式add
和*f
它是一个左值是一样的事情:
标准草稿[expr.prim.id.unqual]
...如果实体是函数,则表达式为左值...
函数符号
add
被传入,而不是人们认为它的指针&add
。现在您可能会说这是因为符号add
是一个指针。
不,那不是原因。
add
不是指针。它是一个左值。但是函数类型的左值会隐式转换为指针(这称为衰减):
标准草稿[转换功能]
函数类型T的左值可以转换为“指向T的指针”的前值。结果是指向该函数的指针。
因此,以下在语义上是等效的:
binary_op(a, b, add); // implicit function-to-pointer conversion
binary_op(a, b, &add); // explicit use of addressof operator
那么,为什么使用语法
(*f)
而不是仅仅语法正确f
?
事实证明,调用函数左值与调用函数指针具有相同的语法:
标准草稿[expr.call]
函数调用是一个后缀表达式,后跟括号,其中包含可能是空的,逗号分隔的初始化程序子句列表,这些子句构成了函数的参数。后缀表达式应具有函数类型或函数指针类型。对于非成员函数或静态成员函数的调用,后缀表达式应为引用函数的左值(在这种情况下,函数到指针的标准转换([conv.func])将被禁止(在后缀表达式上),或者具有函数指针类型。
这些都是相同的函数调用:
add(parameter_list); // lvalue
(*f)(parameter_list); // lvalue
(&add)(parameter_list); // pointer
f(parameter_list); // pointer
PS这两个声明是等效的:
double binary_op(double, double, double (*)(double, double))
double binary_op(double, double, double (double, double))
这是由于以下规则,它与隐式衰减到函数指针相辅相成:
标准草案[dcl.fct]
函数的类型使用以下规则确定。每个参数的类型(包括功能参数包)由其自己的decl-specifier-seq和声明符确定。在确定每个参数的类型之后,将类型为“ T的数组”或函数类型为T的任何参数调整为“指向T的指针” ...
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句