2012-04-24 69 views
2

我想通過傳遞函數指針來獲得像這樣的工作。我知道你只需要將第一個類的指針傳遞給第二個類,然後讓第二個類通過指針觸發第一個類的成員函數。但我不希望第二堂課依靠了解第一堂課是誰。這更像是我想要達到的代碼風格。由於使用函數指針在類之間傳遞數據

////////////////////////////////////////////////// 
class Second 
{ 
public: 
    Second::Second(void (*SecondTriggered)(void)); 
}; 

Second::Second(void (*SecondTriggered)(void)) 
{ 
    SecondTriggered(); 
} 


////////////////////////////////////////////////// 
class First 
{ 
public: 
    First::First(); 
    void SecondTriggered(); 
    Second *second; 
}; 

First::First(){ 
     printf("first class was created"); 
    second = new Second(SecondTriggered); 
} 

void First::SecondTriggered(){ 
    printf("second class was created and responded"); 
} 

///////////////// 
int main() 
{ 
    First *first = new First(); 
} 

我得到這個錯誤:

error C3867: 'First::SecondTriggered': function call missing argument list; 
use '&First::SecondTriggered' to create a pointer to member 

任何想法。

+0

[什麼是你正在嘗試的根本問題解決](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)? – Johnsyweb 2012-04-24 03:47:36

+0

使第二個類能夠觸發First類的成員函數,但不發送指向整個類的指針,只是函數。 – aquawicket 2012-04-24 03:49:48

+0

@dasblinkenlight啊,沒有意識到發生在同一時間。也刪除了我的評論。 – smocking 2012-04-24 12:51:20

回答

3

您正嘗試傳遞一個非靜態類成員,其中需要獨立函數。要做到你嘗試一下,你就必須這樣做,而不是執行以下操作:

class Second 
{ 
public: 
    Second::Second(void (*SecondTriggered)(void*), void *arg); 
}; 

Second::Second(void (*SecondTriggered)(void*), void *arg) 
{ 
    SecondTriggered(arg); 
} 


////////////////////////////////////////////////// 
class First 
{ 
public: 
    First::First(); 
    static void SecondTriggered(void *arg); 
    Second *second; 
    void DoSomething(); 
}; 

First::First(){ 
    printf("first class was created"); 
    second = new Second(&SecondTriggered, this); 
} 

void First::SecondTriggered(void *arg){ 
    printf("second class was created and responded"); 
    static_cast<First*>(arg)->DoSomething(); 
} 

void First::DoSomething(){ 
    printf("first class did something"); 
} 

///////////////// 
int main() 
{ 
    First *first = new First(); 
 } 
+0

好的。這很好。但是現在我無法訪問任何不是靜態的成員。可以用非靜態的SecondTriggered()完成,或者SecondTriggered()可以訪問非靜態成員? – aquawicket 2012-04-24 04:13:10

+1

是的,你可以訪問非靜態成員。 'First :: SecondTriggered()'是'First'的成員,因此它可以訪問所有'First'的成員。傳遞'arg'參數的目的是特別讓你可以訪問非靜態成員。這就是爲什麼我說你可以在需要的時候將這個參數轉換爲'First *'指針。我用一個例子更新了我的答案。 – 2012-04-24 04:26:55

+0

我喜歡這個.. static_cast (arg) - > DoSomething();是我不必告訴第二我是誰的唯一額外。幾乎是我在找的東西。謝謝雷米 – aquawicket 2012-04-24 04:37:20

2

請記住,指向成員函數和函數指針有很大的不同。你必須有一個對象來調用指向成員函數的指針。如果您想使用成員函數指針,下面的代碼工作(我只顯示了語法,讓您的代碼工作使用指針的成員函數之前,我會建議瞭解C++的概念。):

#include <stdio.h> 
////////////////////////////////////////////////// 
class First; // Forward declaration needed 

class Second 
{ 
public: 
    Second(void (First::*SecondTriggered)(void), First& f); 
}; 

Second::Second(void (First::*SecondTriggered)(void), First& f) 
{ 
    (f.*SecondTriggered)(); 
} 


////////////////////////////////////////////////// 
class First 
{ 
public: 
    First(); 
    ~First() { delete second;} // Fix memory leak 
    void SecondTriggered(); 
    Second *second; 
}; 

First::First(){ 
    printf("first class was created\n"); // What are you using printf in C++? 
    second = new Second(&First::SecondTriggered, *this); 
} 

void First::SecondTriggered(){ 
    printf("second class was created and responded\n"); 
} 

///////////////// 
int main() 
{ 
    First first; // No reason to use new here 
} 

請閱讀this faq瞭解更多信息。

2

您應該閱讀How do I implement a callback in C++?並特別注意對Observer Pattern的引用。如果你有兩個這樣緊密耦合的類,那麼你可能想重新考慮你的設計,因爲測試它們很快就會變成一場噩夢。

這就是說,這裏是如何完成你開始實施......

#include <iostream> 

class First; 

// Typedefs make this much more readable: http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.5 
typedef void (First::*SecondTriggeredCallback)(void); 

// And macros make the call much more readable: http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.6 
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember)) 

class Second 
{ 
public: 
    // You'll also need an *instance* of the First class 
    Second(SecondTriggeredCallback SecondTriggered, First& first) 
    { 
     CALL_MEMBER_FN(first, SecondTriggered)(); 
    } 
}; 

class First 
{ 
private: 
    Second *second; 

public: 
    First() 
    { 
     std::cout << "first class was created" << std::endl; 
     second = new Second(&First::SecondTriggered, *this); 
    } 

    ~First() 
    { 
     delete second; 
    } 

    void SecondTriggered() 
    { 
     std::cout << "second class was created and responded" << std::endl; 
    } 
}; 

int main() 
{ 
    First first; 
} 

See it run


這裏有一個版本,通過使用模板移除耦合:

#include <iostream> 

// Macros make the call much more readable: http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.6 
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember)) 
template <class T> 
struct Second 
{ 
    // Typedefs make this much more readable: http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.5 
    typedef void (T::*SecondTriggeredCallback)(void); 

    // You'll also need an *instance* of the "T" class 
    Second(SecondTriggeredCallback SecondTriggered, T& t) 
    { 
     CALL_MEMBER_FN(t, SecondTriggered)(); 
    } 
}; 

class First 
{ 
public: 
    First() 
     :second(NULL) 
    { 
     std::cout << "first class was created" << std::endl; 
     second = new Second<First>(&First::SecondTriggered, *this); 
    } 

    ~First() 
    { 
     delete second; 
    } 

    void SecondTriggered() 
    { 
     std::cout << "second class was created and responded" << std::endl; 
    } 

private: 
    First(const First&); 
    First& operator =(const First&); 
    Second<First>* second; 
}; 

int main() 
{ 
    First first; 
} 
+1

非常好,乾淨,我喜歡這個。謝謝 – aquawicket 2012-06-04 01:26:23

+0

非常好。 – rahman 2013-05-02 07:17:49

+1

謝謝@rahman。當然,這個代碼可以通過使用智能指針進一步降低。例如:http://ideone.com/129OJo – Johnsyweb 2013-05-02 09:46:44

1

您也可以考慮通過一個函數對象:

class t_func { 
protected: 
    t_func() { 
    } 

    virtual ~t_func() { 
    } 

public: 
    virtual void operator()() = 0; 
private: 
    t_func(const t_func&) = delete; 
    t_func& operator=(const t_func&) = delete; 
}; 

class Second { 
public: 
    Second(t_func& func); 
}; 

Second::Second(t_func& func) { 
    func(); 
} 

class First { 
public: 
    First(); 
private: 
    void SecondTriggered(); 
    Second* second; 
}; 

First::First() { 
    printf("first class was created\n"); 

    class t_trigger : public t_func { 
    public: 
     t_trigger(First& pFirst) : t_func(), first(pFirst) { 
     } 

     virtual void operator()() { 
      return first.SecondTriggered(); 
     } 

    private: 
     First& first; 
    }; 

    t_trigger trig(*this); 
    second = new Second(trig); 
} 

void First::SecondTriggered() { 
    printf("second class was created and responded\n"); 
} 

int main() { 
    First* first = new First(); 

    delete first; 
    return 0; 
}