C++ -- Questions about function pointers
I have written the following code:
#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;
}
I have run the above code on VS2008 and each function call returns '100'. Here is the questio开发者_运维问答n:
Q1> Is there any problem in the code?
Q2> It seems that C++ doesn't make difference between *pf and pf. Is that correct?
Thank you
C++ does, in fact, make a distinction between the types double()
and double(*)()
, but the difference is subtle. When you pass a function type as an argument to a function, the function-type automatically "degrades" to a function pointer. (This is similar, I suppose, to how an array type degrades to a pointer type when passed as a function argument.)
However, a function type and a function-pointer type are still different types, according to the C++ type-system. Consider the following case:
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();
}
This should fail to compile, since you cannot declare a function type as an automatic variable. (Remember, functions are not first-class objects in C++.) So the declaration F func;
is invalid. However, if we change our main
function to instead instantiate the template using a function pointer, like so:
int main ()
{
typedef void(*function_pointer)();
Foo<function_pointer> f(g);
f();
}
...now it compiles.
The following functions are identical:
int g(double (*pf)())
{
cout << (*pf)() << endl;
return 0;
}
int g2(double pf())
{
cout << pf() << endl;
return 0;
}
Dereferencing a function pointer (as shown in g) is the same as calling that function's name.
Q2> It seems that C++ doesn't make difference between *pf and pf. Is that correct?
There is a difference between *pf and pf (as variables). If pf is a function, *pf and pf() are identical (Note the parentheses).
With most modern compilers, there is no difference between "(*variable)." and "variable->". However, one must check the class in use to see if it overrides the dereference operator.
Many programmers use typedef
when defining function pointers, primarily to make reading easier. Also, the double pf()
syntax may be prone to readability errors and can get confused with executing a function on parameter line.
There's no problem or difference in the code you posted. However, if you are writing templates which take functors, you should use the syntax in g2. Consider the following:
template<typename Iter, typename Func>
void for_each(Iter begin, Iter end, Func functor)
{
for(; begin != end; ++begin)
{
functor(*begin);
}
}
Note that if you put the dereference operator before functor
, you limit the utility of the algorithm you have written to function pointers. However, if you don't put that there, someone can pass an STL functor, such as something returned by std::bind2nd
.
Therefore I would overall recommend using the second (without *
) syntax where possible.
Consider the following piece of code
void pf();
void (&prf)() = pf; // OK, bind prf to pf
void (&prf)() = &pf; // ill-formed, can't bind prf to an function pointer value
On the other hand
void (*ppf)() = pf; // OK, function decays to a pointer
void (*ppf)() = &pf; // OK, pointer assigned to a pointer
So there is an implicit conversion from a function to a pointer (which is called "decay"). This also makes you able to say ***...***pf
- arbitrarily many times dereference it - in each step a function to pointer conversion occurs which undoes the effect of the previous dereference.
In function parameter lists, a T f()
and a T (*f)()
are equivalent ways (except for spelling) of declaring a parameter
void f(void g()); // g has type void (*)()
void f(void (*g)()); // g has type void (*)()
A reference will inhibit this parameter type adjustment
void f(void (&g)()); // g has *not* the type void (*)()
This is exactly the same as for array declared parameters: Parameters are never arrays, but they will always be pointers, if they were declared as being arrays.
精彩评论