指向程序的指针

时间:2012-08-09 14:32:50

标签: c++ function-pointers

是否可以通过指针调用过程?我没有在互联网上找到任何关于它的信息,但是下面的实验代码在没有警告的情况下编译。

#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有点“透明”。

4 个答案:

答案 0 :(得分:5)

C和C ++都有函数指针,可以让你做你想要的事情:

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

括号中的void是可选的。

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

答案 1 :(得分:4)

你想要的是函数指针

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

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

请注意,正如您所看到的,函数指针有一个非常笨拙的语法(特别是如果您开始使用带有“奇怪”参数的函数指针)并且可以阻止某些编译器优化正常工作,因此它们通常仅在实际上需要(例如,对于回调,虽然在C ++中通常首选仿函数)。


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

void* pF = PrintCurrentClock;

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

pF;

您正在评估表达式pF并丢弃其返回值 - 这实际上是一个无操作(就像您编写5;或任何其他不涉及函数调用的表达式一样)。


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

    matteo@teolapmint ~/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");无法移植)。

答案 2 :(得分:2)

您创建和使用函数指针的方式稍微偏离。以下是如何执行此操作的示例:

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

...

void (*pproc)() = proc;

pproc();

答案 3 :(得分: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。这些基本上是可以定义的功能。但是将lambda视为编译器生成的仿函数更容易(因为它们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.