2011-08-28 281 views
6

我有2點C++類的問題:傳遞一個類的成員函數作爲函數參數

的第一個問題是:我怎樣才能使這樣我就可以在另一個函數&傳遞類成員函數作爲參數我怎麼才能運行/調用該功能?我怎樣才能做到類靜態函數。它也許更容易被看這個代碼明白我的問題:

class DebuggingManager 
{ 
    string testLog; 

    bool test1() 
    { 
     // run test & return whether it passed or failed 
    }  

    static bool test2() 
    { 

    } 

    // How can I call a member function? 
    void catalogueTest(string testName, bool DebuggingManager::*nMemberFunction) 
    { 
     testLog += "Status of " + testName + ": " + ((*)nMemberFunction()) + "\n"; 
    } 

    // How can I call a static function? 
    void catalogueTest(string testName, bool DebuggingManager::*nStaticFunction) 
    { 
     testLog += "Status of " + testName + ": " + DebuggingManager::nStaticFunction() + "\n"; 
    } 

    // how do I pass a member function or a static function as a parameter in another function 
    bool runTests() 
    { 
     catalogueTest("Test of member functin", test1()); 
     catalogueTest("Test of static functin", test2()); 
    } 

}; 

的第二個問題是:是否有不良(或危險)的做法調用類成員(或靜態)函數間接就像上面。我有一種感覺,這是非常糟糕的C++的做法?

編輯:實施意見 感謝您的答覆,我試圖實現他的意見,它的很多我的頭左右,雖然,這會是正確的嗎?

// I have a feeling that ParameterList is incorect, would I pass the implicit obj as a parameter or is it done automatically like in normal object function calls? 
    typedef bool (DebuggingManager::*MemberPointerType)(ParameterList); 

    void catalogueTest(tstring testName, DebuggingManager* obj, MemberPointerType *nMemberFunction) 
    { 
     debugLog += _T("Status of ") + testName + _T(": ") + (obj->*nMemberFunction)() + _T("\r\n"); 
    } 

    void catalogueStaticTest(tstring testName, bool DebuggingManager::nStaticFunction) 
    { 
     debugLog += _T("Status of ") + testName + _T(": ") + nStaticFunction + _T("\r\n"); 
    } 
+1

我很驚訝,這不是已經回答也許其他人是累過,不希望查找第500次成員函數指針的語法。 –

+1

請參閱http:// stackoverflow。com/questions/2463112 /指向ac-class-member-function-as-a-global-functions-parameter的鏈接http://www.parashift.com/c++-faq-lite/pointers- to-members.html在聲明/使用普通和靜態成員函數指針時有注意的語法和注意事項。至於是否壞,我會說:可能不是在特定情況下(如測試或其他人),但作爲編寫代碼的日常練習並不是一件好事,因爲它很棘手,並且因爲對於大多數您可以使用它們的任何東西都有更好的機制。 – shelleybutterfly

回答

13

類的靜態成員函數最終沒有不同於普通函數。他們真的只是語法糖;該功能只是有一個名稱,其中包括Classname::

非靜態成員完全是另一回事。關於非靜態成員函數(NSMF)有兩件重要的事情要記住。首先,每個非靜態成員函數都可以訪問它們所屬的類的非靜態成員。即使可以有兩個同一類的對象存儲不同的數據,這也是可能的。如果您有兩個std::string對象,則它們每個都存儲不同的字符串。對一個字符串執行find可以在一個字符串中返回找到的結果,但不會在另一個字符串中返回。

這是因爲每個NSMF都有一個隱含的指針thisthis指的不僅僅是一個類,而是NSMF在其上運行的實際的對象。當你這樣做:

std::string aString("data"); 
aString.find("da"); 

find功能需要一個字符串參數,但它也得到aStringthis。每次find尋找其班級的成員,它會查看aString的數據。

因此,讓我們看看你的NSMF的前瞻性電話:

((*)nMemberFunction()) 

在哪裏對象,它得到了this指針的?沒有對象,NSMF無法訪問該對象的非靜態成員,因爲沒有對象可供它找到它們。這是不合法的。

因此,有關NSMF的規則#1:您必須使用NSMF所屬的類的實際實例(或其派生類)調用它們。你不能只帶一個NSMF指針,並把它稱爲函數指針;您必須在該類型的實時對象上調用它。

規則2:NSMF指針的語法真的很難看。

定義一個名爲NSMF指針類型的arg變量(或參數),你這樣做:

ReturnType (ClassName::*arg)(ParameterList); 

哪裏ReturnType是函數的返回類型,ParameterList是函數取的參數列表,並且ClassName是NSMF指針所屬的類的名稱。

鑑於醜陋,通常最好將其包裝在一個typedef:

typedef ReturnType (ClassName::*MemberPointerType)(ParameterList); 

因此創建的typedef MemberPointerType,這是一個NSMF指針。

給定一個名爲object的對象,這是ClassName型的,你會調用成員指針arg如下:

ReturnType value = (object.*arg)(Params); 

哪裏Params是你要傳遞的參數。如果object是指向ClassName而不是參考或值的指針,則代之以使用object->*arg

還有一件事:你必須使用&得到成員指針名稱。與函數指針不同,NSMF指針不會自動轉換爲成員指針。你必須直接詢問他們。所以,如果ClassName有一個成員叫功能適合上述ReturnTypeParameterList,你將填補arg如下:

arg = &ClassName::Function; 

規則#3:非靜態成員指針不是指針。是的,他們可以設置爲NULL(技術上,它們可以設置爲0),但它們是而不是與指針相同。

大多數真正的C和C++編譯器將允許您將函數指針投射到void*之後。標準認爲這種未定義的行爲,但這並不完全未知。你絕對是不能用在NSMF指針上做這件事,幾乎所有的C++編譯器都這樣做。的確,sizeof(MemberPointerType)的尺寸可能不會與void*的尺寸相同。

因此,NSMF指針不是常規指針。不要這樣對待他們。

+0

難道你不得不說'(object。* arg)(Params);'因爲運算符優先級? –

+0

@Kerrek SB:是的,'。*'的優先級低於函數調用的優先級。 –

+0

@Nicol Bolas:謝謝你的回覆。我試圖實現你所說的,這是對的嗎? – user593747

2

在C++ 11中,他們想出了一個辦法。閱讀有關functionbind的操作。

就你而言,假設你想調用test1類型的函數。 (即形式布爾使用functionName()的

void catalogueTest(string testName, std::function<bool()> myFunction) 
{ 
    testLog += "Status of " + testName + ": " + myFunction() + "\n"; 
} 

,並調用它是這樣的:

DebuggingManager myInstance 
myInstance->catalogueTest("TestName", std::bind(&DebuggingManager::test1, myInstance)); 
相關問題