2012-08-09 113 views
3

是否可以通过指针调用过程?我在互联网上没有发现任何关于它的内容,但下面的实验代码编译时没有警告。指向过程的指针

#include <iostream> 
#include <ctime> 

using namespace std; 

void PrintCurrentClock() 
{ 
    cout<<clock()<<endl; 
} 

void PrintCurrentTimeStamp() 
{ 
    cout<<time(0)<<endl; 
} 


int main() 
{ 
    void* pF = PrintCurrentClock; 

    pF; 

    pF = PrintCurrentTimeStamp; 

    pF; 

    system("Pause"); 
    return 0; 
} 

输出为空,就好像*pF有些“透明”一样。

+0

[C++不具有程序,它具有的功能](https://www.google.com/#q=call%20function%20via %20pointer%20c%2B%2B) – 2012-08-09 14:35:14

+0

指向函数的指针称为[函数指针](http://en.wikipedia.org/wiki/Function_pointer),是的,可以通过函数指针调用函数。 – 2012-08-09 14:35:18

+1

为了这个问题,将“FunctionWithVeryVeryVeryLongNameThatPrintsTheCurrentClockStateUsingStdCoutOutputStream”的名称缩短为“print_clock_state”太难了吗? – mfontanini 2012-08-09 14:36:20

回答

5

C和C++有函数指针,让你做你在找什么:

void (*pf)(void); 
pf = FunctionWithVeryVeryVeryLongNameThatPrintsTheCurrentClockStateUsingStdCoutOutputStream; 
pf(); 

圆括号中的void是可选的。

您没有找到关于该主题的任何内容的原因是,由于历史原因,C中的函数和过程都称为函数(原因是原始语言中没有void - 过程返回int默认情况下,返回值被忽略)。 C++继承了这个命名约定。

2

您的创建和使用函数指针的方法稍微偏离。下面是如何做到这一点的例子:

void proc() { 
    cout << "Hello from proc" << endl; 
} 

...

void (*pproc)() = proc; 

pproc(); 
4

你想要什么是函数指针

void (*pF)() = PrintCurrentClock; 
pF(); 

(有些人认为,写&PrintCurrentClock是更好的风格)

注意,你可以看到,函数指针有一个比较尴尬的语法(尤其是如果你开始拥有带有“奇怪”参数的函数指针),并且可以防止某些编译器优化工作正常,所以它们通常只在实际需要时才使用(例如,对于回调,尽管在C++函子中经常是首选)。


为什么你的代码编译,虽然它不按预期工作?在

void* pF = PrintCurrentClock; 

PrintCurrentClockvoid (*pF)(),这是隐式转换为void * ;然后,写

pF; 

你正在评估表达pF并丢弃其返回值 - 这实际上是一个无操作(完全一样,如果你写5;或其他任何表情,不涉及一个函数调用)。


  1. 事实上,这种转换应该不会自动从C++标准不从函数指针void *提供的隐式转换发生。用g ++编译这个4。6正确地产生错误:

    [email protected] ~/cpp $ g++ -Wall -Wextra -ansi -pedantic testfuncptr.cpp 
    testfuncptr.cpp: In function ‘int main()’: 
    testfuncptr.cpp:19:20: error: invalid conversion from ‘void (*)()’ to ‘void*’ [-fpermissive] 
    testfuncptr.cpp:21:15: warning: statement has no effect [-Wunused-value] 
    testfuncptr.cpp:23:22: error: invalid conversion from ‘void (*)()’ to ‘void*’ [-fpermissive] 
    testfuncptr.cpp:25:23: warning: statement has no effect [-Wunused-value] 
    testfuncptr.cpp:27:39: error: ‘system’ was not declared in this scope 
    

    它告诉你,那些转换是不承认,该pF;说明空操作,并且您忘记#include <cstdlib>(虽然system("pause");是不可移植反正)。

+1

注意(对于OP),_evaluating表达式'pF'_ does ** not **意味着_calling_函数'pF'指向。这只是一种无所作为的表达。 – Useless 2012-08-09 14:45:31

1

是,您可以:

虽然类型系统是一个有点令人费解。
所以通常在typedef中包装一个指向函数的指针。

typedef <returnType> (*<TypeName>)(<ParameterList>); 

// In your case: 

tpyedef void (*PtrToTimeFunc)(); 

// Now your pointer types look like normal variables: 
PtrToTimeFunc pf = &PrintCurrentTimeStamp; 

// Calling them is like normal: 
pf(); // If it needed parameters then put them as normal. 

因为C++编译器不能通过函数指针来优化代码;在C++中,通常使用函子。仿函数是一个像函数那样行为的对象,但是因为它是一个对象也可以包含状态(就像其他语言中的闭包)。

struct MyFunctor 
{ 
    // To make a functor just override the operator() 
    // You can make it return any type and take any parameters (just like a function). 
    int operator()() const 
    { 
     return time(NULL); 
    } 

    // Add any state and constructors etc. you like here. 
    // Though note: because I declared the operator() as const you 
    // can not mutate the state via the function call (remove cost) 
    // if you want to do that. 
}; 

// declaring a functor just like any-other object. 
MyFunctor myFunctor; 

// calling. Just like a function. 
myFunctor(); 

好的。那么为什么这比指针更有用。

与标准算法一起使用时。您可以使用functor的类型定义算法,因此编译器会生成算法代码,它也具有函数的所有代码(与函数指针不能优化过去不同)。这使编译器能够完成一整套优化。

std::generate(cont.begin(), cont.end(), myFunctor); 

所以在C++ 11中,我们引入了lambdas。这些基本上是可以定义的功能。但将lambdas当作编译器生成的函子会更容易(因为它们将can作为其定义的一部分捕获当前状态)。

std::generate(cont.begin(), cont.end(), [](){return time(NULL);}); 

// [] - defines the state that is being captured. 
//  Think of this like the constructor capturing objects. 
//  In this case take no state. 
// 
//() - parameter list 
//  In this case no parameters 
// 
// {} - The code. 

一个更有趣的例子:

std::vector<int> data; // fill vector 
std::for_each(data.begin(), data.end(), [](int& value){value += 4;}); // Add 4 to each member.