我写了以下代码:
#include "stdafx.h"
#include <iostream>
using namespace std;
double funcA()
{
return 100.0;
}
int g(double (*pf)())
{
cout << (*pf)() << endl;
return 0;
}
int g2(double pf())
{
cout << pf() << endl;
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
g(&funcA); // case I
g(funcA); // case II
g2(funcA); // case III
g2(&funcA); // case IV
return 0;
}
我在VS2008上运行了上面的代码,每个函数调用返回'100'。 这是一个问题:
Q1&GT;代码中有问题吗?
Q2&GT;似乎C ++在* pf和pf之间没有区别。这是对的吗?
谢谢
答案 0 :(得分:8)
C ++ 确实区分了double()
和double(*)()
类型,但区别是微妙的。将函数类型作为参数传递给函数时,函数类型会自动“降级”为函数指针。 (我想,这与数组类型在作为函数参数传递时如何降级为指针类型类似。)
但是,根据C ++类型系统,函数类型和函数指针类型仍然是不同的类型。考虑以下情况:
void g() { }
template <class F>
struct Foo
{
Foo(const F& f) : func(f)
{ }
void operator()() { func(); }
F func;
};
int main ()
{
Foo<void()> f(g);
f();
}
这应该无法编译,因为您不能将函数类型声明为自动变量。 (请记住,函数不是C ++中的第一类对象。)因此声明F func;
无效。但是,如果我们将main
函数更改为使用函数指针来实例化模板,如下所示:
int main ()
{
typedef void(*function_pointer)();
Foo<function_pointer> f(g);
f();
}
...现在它编译。</ p>
答案 1 :(得分:2)
以下功能相同:
int g(double (*pf)())
{
cout << (*pf)() << endl;
return 0;
}
int g2(double pf())
{
cout << pf() << endl;
return 0;
}
取消引用函数指针(如g所示)与调用该函数的名称相同。
Q2&GT;似乎C ++没有 * pf和pf之间的差异。就是它 正确的吗?
* pf和pf(作为变量)之间存在差异。如果pf是一个函数,* pf和pf()是相同的(注意括号)。
答案 2 :(得分:0)
对于大多数现代编译器,“(* variable)”之间没有区别。和“变量 - &gt;”。但是,必须检查正在使用的类以查看它是否覆盖取消引用运算符。
许多程序员在定义函数指针时使用typedef
,主要是为了使阅读更容易。此外,double pf()
语法可能容易出现可读性错误,并且可能与在参数行上执行函数混淆。
答案 3 :(得分:0)
您发布的代码没有问题或不同之处。但是,如果您正在编写带有仿函数的模板,则应使用g2中的语法。请考虑以下事项:
template<typename Iter, typename Func>
void for_each(Iter begin, Iter end, Func functor)
{
for(; begin != end; ++begin)
{
functor(*begin);
}
}
请注意,如果将解除引用运算符放在functor
之前,则会限制已写入函数指针的算法的效用。但是,如果你不把它放在那里,有人可以传递一个STL仿函数,例如std::bind2nd
返回的东西。
因此,我总体建议尽可能使用第二种语法(没有*
)。
答案 4 :(得分:0)
考虑以下代码
void pf();
void (&prf)() = pf; // OK, bind prf to pf
void (&prf)() = &pf; // ill-formed, can't bind prf to an function pointer value
另一方面
void (*ppf)() = pf; // OK, function decays to a pointer
void (*ppf)() = &pf; // OK, pointer assigned to a pointer
因此存在从函数到指针的隐式转换(称为“衰减”)。这也使你能够说***...***pf
- 任意多次取消引用它 - 在每一步中都会发生指针转换的函数,这会撤消前一个解除引用的影响。
在函数参数列表中,T f()
和T (*f)()
是声明参数的等效方式(拼写除外)
void f(void g()); // g has type void (*)()
void f(void (*g)()); // g has type void (*)()
参考将禁止此参数类型调整
void f(void (&g)()); // g has *not* the type void (*)()
这与数组声明的参数完全相同:参数永远不是数组,但如果它们被声明为数组,它们将始终是指针。