2012-04-24 44 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; 
}