2012-08-09 83 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.