2012-04-24 19 views
2

私は関数ポインタを渡すことでこのようなことをしようとしています。あなたは、最初のクラスのポインタを2番目のクラスに渡すだけで、1番目のクラスのメンバ関数をポインタで呼び出すことができます。しかし、私は第二のクラスが第一のクラスが誰であるかを知ることに頼ることを望まない。これは私がこれを達成するために探しているコーディングスタイルによく似ています。おかげ関数ポインタを使ってクラス間でデータを渡す

////////////////////////////////////////////////// 
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

+0

第2クラスをファーストクラスのメンバ関数を起動させることができますが、関数全体のクラス全体へのポインタは送信しません。 – aquawicket

+0

@dasblinkenlightああ、その間に起こったことを知らなかった。私のコメントも削除しました。 – smocking

答えて

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

+1

はい、非静的メンバーにアクセスできます。 'First :: SecondTriggered()'は 'First'のメンバであり、' First'のメンバすべてにアクセスできます。 'arg'パラメータを渡す目的は、特に非静的メンバーにアクセスできるようにするためです。そのため、必要に応じて、そのパラメータを 'First * 'ポインタに型キャストすることができます。私は答えを例で更新しました。 –

+0

私はこれが好きです.. static_cast (arg) - > DoSomething();私が誰であるのかを第二に伝えることなく、私がしなければならない唯一の余分なものです。かなり私が探していたもの。ありがとうレミー – aquawicket

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への参照に特に注意してください。このような緊密に結合されたクラスが2つある場合は、テストがすぐに悪夢になるため、デザインを再考することをお勧めします。ここでは、言った

#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

+0

非常にきれいに置く。 – rahman

+1

ありがとう@rahman。もちろん、スマートポインタを使用することでこのコードをさらに減らすことができます。例:http://ideone.com/129OJo – Johnsyweb

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; 
} 
関連する問題