2015-01-26 4 views
0

Я разрабатываю приложение, которое использует один класс для управления TCP-соединением и один для управления элементами пользовательского интерфейса. Менеджер соединений получает строки сообщений и выполняет минимальную обработку для определения их типа. Если они имеют известный тип, диспетчер соединений передаст строки вместе с менеджером графического интерфейса, чтобы он мог соответствующим образом обновлять элементы интерфейса.Совместное использование функций-членов между классами

Мой вызов: если я не хочу включать файлы заголовков через классы, как разрешить доступ к публичным функциям другого класса?

Например:

//message_types.h 
typedef void(*MessageHandlerPointer)(std::string); 

enum MessageTypes { info_type, time_type, command_type, reply_type, 
        inside_type, update_type, NUM_TYPES }; 
///////////////////////////////////////////////////////////////////////// 
//ConnectionManager.h 
class ConnectionManager 
{ 
    string hostname; 
    string port; 
    int connection_fd; 

    string message_types[NUM_TYPES]; 
    string partial_message; 

    void process_message(string message); 
    MessageHandlerPointer message_handlers[NUM_TYPES]; 

    public: 
    ConnectionManager(string hostname, string port); 
    ~ConnectionManager(); 

    int connect(); 
    void disconnect(); 
    void listen(); 
}; 
///////////////////////////////////////////////////////////////////////// 
//ConnectionManager.cpp 
ConnectionManager::ConnectionManager(string hostname, string port, 
        void (*message_handlers[NUM_TYPES])(string)): 
    hostname(hostname), port(port), 
    message_types { "i", "t", "c", "r", "I", "u" } 
{ 
    for(int i = 0; i < NUM_TYPES; i++) 
    { 
    this->message_handlers[i] = message_handlers[i]; 
    } 
} 
///////////////////////////////////////////////////////////////////////// 
//GuiManager.h 
class GuiManager 
{ 
    void info_handler(string msg); 
    void time_handler(string msg); 
    void command_handler(string msg); 
    void reply_handler(string msg); 
    void inside_handler(string msg); 
    void update_handler(string msg); 

    public: 
    GuiManager(); 
    ~GuiManager(); 

    MessageHandlerPointer message_handlers[NUM_TYPES]; 
}; 
///////////////////////////////////////////////////////////////////////// 
//GuiManager.cpp 
GuiManager::GuiManager() 
{ 
    message_handlers[info_code] = &info_handler; 
    message_handlers[time_code] = &time_handler; 
    message_handlers[command_code] = &command_handler; 
    message_handlers[reply_code] = &reply_handler; 
    message_handlers[inside_code] = &inside_handler; 
    message_handlers[update_code] = &update_handler; 
} 
///////////////////////////////////////////////////////////////////////// 
//generic main.cpp 
int main() 
{ 
    GuiManager gm(); 
    ConnectionManager cm("host", "45123", gm.message_handlers); 
} 

Но C++ не хочет, чтобы сделать это, и я смутно понимаю, почему. Функции-члены не являются свободными функциями. Но я надеялся, что, возможно, некоторые функции станут владельцами или классами-агностиками?

В любом случае, моя идея не собирается заставлять меня, где я хочу быть, поэтому я был бы рад услышать чужое впечатление о том, какое лучшее решение будет.

Кроме того, я признаю, что я могу быть немного смешным для модульности, не позволяя классам взаимодействовать друг с другом напрямую. Я пропустил принципиальную цель/жертвуя простотой?

Я довольно новичок в OO, поэтому меня интересуют все детали любого ответа. =)

+1

'gm' является функцией. –

+0

из-за [наиболее раздражающего разбора] (http://en.wikipedia.org/wiki/Most_vexing_parse). – Axalo

+1

'Если я не хочу включать заголовочные файлы через объекты, как разрешить доступ к публичным функциям другого объекта?» Хотя я, безусловно, могу понять, что C++ предоставил разумную альтернативу заголовкам, простой факт заключается в том, что он не делает «т. Несмотря на свои проблемы, заголовок - это, безусловно, правильный способ сделать это. –

ответ

1

Итак, если у меня есть это право, вы хотите, чтобы ваш диспетчер соединений перенаправлял сообщения в ваш GUIManager, но без необходимости включать заголовок GUIManager, просто используя форвардные объявления.

На месте вы застряли в том, что, как вы заметили, тип

void GUIManager::handle_info(std::string) 

, который отличается от типа указателя на функцию свободного

void handle_info (std::string). 

Чтобы объявить указатель на бывший вам необходимо написать

typedef void (GUIManager::*MessageHandlerPointer)(string); 

Я написал упрощенный пример (с Foo и Bar :)), wher e экземпляр Bar пересылает сообщение экземпляру Foo. Вот оно:

#include <iostream> 
#include <string> 

using namespace std; 

class Foo; 
typedef void (Foo::*FooMessageHandlerPointer)(string);  // this is the type of a pointer to a member of Foo that gets a string and returns void. 

class Bar 
{ 
public: 
    Bar (Foo* foo_, FooMessageHandlerPointer ptr) 
    : 
    foo (foo_), 
    p (ptr) 
    {} 

public: 

    void ForwardMessage (string s) 
    { 
     (foo->*p)(s); 
    } 

private: 

    Foo* foo; 
    FooMessageHandlerPointer p; 
}; 


class Foo 
{ 
public: 

    void ProcessMessage (string s) 
    { 
     cout << "Foo received: " << s << "\n"; 
    } 
}; 


int main (void) 
{ 
    Foo foo1; 

    Bar bar1 (&foo1, &Foo::ProcessMessage); 

    bar1.ForwardMessage("Hello world!"); 

    return 0; 
} 

Обратите внимание, что когда Бар определен, он имеет в своем распоряжении только опережающее объявление о Foo и тип указателя функции-члена. Обратите внимание также, что для Bar требуется не только указатель на функцию, но также указатель на экземпляр. Конечно, когда вы создаете экземпляр Bar в основном, вам нужно иметь доступ к заголовкам.

Надеюсь, у меня есть вопрос правильно, и это поможет вам. В противном случае это было хорошее упражнение, так как в наши дни я играл с указателями на функции-члены :)

ОБНОВЛЕНИЕ: . После вашего комментария, я думаю, вы можете искать что-то вроде делегата, что-то, что инкапсулирует функцию для вызова, независимо от того, является ли это свободной или членной функцией. Может быть this нить будет полезна

+0

Хм. Разумеется, вы правы в конфликте типов, но я предусмотрел решение, в котором бары смогут отправлять сообщения в Foos, даже не нуждаясь в том, чтобы знать о внутренних функциях Foo. – musasabi

+0

В моем примере, Bar не знает о внутренностях Foo. У него есть только декларации. В main() Bar настраивается с помощью указателя на функцию, поэтому его единственная функция, которая знает интерфейс Foo. Как ваш пример. – opetroch

+0

Интересно. Возможно, меня повесили на указатель Foo, который живет внутри бара? Это похоже на ту взаимозависимость, которую я пытаюсь избежать. – musasabi

Смежные вопросы