2012-04-24 5 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

+0

Сделать второй класс способным запускать функцию-член первого класса, но без посылки указателя на весь класс поверх. Просто функция. – 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(); это единственное дополнение, которое я должен сделать, не говоря во-вторых, кто я. Очень многое, что я искал. Спасибо Remy – 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. Если у вас есть два таких тесно связанных класса, тогда вы, вероятно, захотите переосмыслить свой дизайн, так как тестирование их скоро станет кошмаром.

Это говорит, вот как завершить реализацию, что вы начали ...

#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; 
} 
Смежные вопросы