我正在设计一个应用程序,它使用一个类来管理TCP连接,另一个用于管理UI元素。连接管理器接收消息字符串并对它们进行最少的处理以确定它们的类型。如果它们是已知类型,则连接管理器会将字符串传递给GUI管理器,以便相应地更新UI元素。
我的挑战是:如果我不想在课程中包含头文件,我如何允许访问其他课程的公共功能?
例如:
//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相当新,所以我对任何答案的所有细节都感兴趣。 =)
答案 0 :(得分:1)
因此,如果我有这个权利,您希望您的ConnectionManager将消息转发到您的GUIManager,但不必包含GUIManager的标头,只需使用前向声明。
当你注意到
的类型时,你会遇到困难void GUIManager::handle_info( std::string )
与指向自由函数的指针类型不同
void handle_info (std::string).
要声明指向前者的指针,您必须编写
typedef void (GUIManager::*MessageHandlerPointer)(string );
我写了一个简化的例子(使用Foo和Bar :)),其中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;
}
请注意,当定义了Bar时,它只能使用Foo的前向声明和成员函数指针的类型。 另请注意,Bar不仅需要指向函数的指针,还需要指向实例的指针。当然,当您在main中创建Bar实例时,您需要有权访问标题。
我希望我的问题正确,这对你有帮助。否则这是一个很好的练习,因为我这些天一直在玩指向成员函数的指针:)
更新: 在您发表评论之后,我认为您可能正在寻找类似委托的东西,包含要调用的函数,无论是免费还是成员函数。也许this主题会有所帮助