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

4

4 回答 4

5

C 和 C++ 都有函数指针,可让您执行所需的操作:

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

void括号中的是可选的。

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

于 2012-08-09T14:37:11.603 回答
4

你想要的是函数指针

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

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

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


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

void* pF = PrintCurrentClock;

PrintCurrentClock是 a void (*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");无论如何都不是便携式的)。

于 2012-08-09T14:37:28.270 回答
2

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

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

...

void (*pproc)() = proc;

pproc();
于 2012-08-09T14:36:32.453 回答
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.
于 2012-08-09T15:45:24.287 回答