我正在寻找 Python PubSub 库的 C++ 替代品,在该库中我不必将信号与插槽左右连接,而是可以注册一种特殊的消息,而不知道可以发送它的对象。
Andre
问问题
1713 次
3 回答
2
也许你误解了什么是信号和插槽。使用信号和插槽,您不必知道谁发送信号。您的“客户端”类只声明插槽,外部管理器可以将信号连接到它们。
我建议您查看 Qt。这是一个了不起的跨平台库,不仅仅支持 GUI。它有一个方便有效的信号和槽实现,你可以使用它。
如今,它还获得了 LGPL 的许可(除了 GPL 和商业),因此您几乎可以将它用于任何目的。
重新澄清您的评论,为什么不对错误提出异常?父母可以通知 GUI,或者 GUI 可以注册父母发出的信号。这样,父母也不必了解 GUI。
于 2009-03-03T18:51:31.507 回答
2
你可以使用boost库吗?如果是这样,那么结合函数和绑定库允许您执行以下操作。如果您的编译器支持,您可以使用 tr1 功能执行相同的操作。
#include <iostream>
#include <list>
#include <boost/function.hpp>
#include <boost/bind.hpp>
typedef boost::function< void() > EVENT_T ;
template<typename F>
class Subject
{
public:
virtual void attach ( F o )
{
obs_.push_back ( o );
}
virtual void notify()
{
for ( typename std::list<F>::iterator i = obs_.begin(); i != obs_.end(); ++i )
( *i ) ();
}
private:
std::list<F> obs_;
} ;
class Button : public Subject<EVENT_T>
{
public:
void onClick()
{
notify() ;
};
};
class Player
{
public:
void play()
{
std::cout << "play" << std::endl ;
}
void stop()
{
std::cout << "stop" << std::endl ;
}
};
class Display
{
public:
void started()
{
std::cout << "Started playing" << std::endl ;
}
};
Button playButton ;
Button stopButton ;
Player thePlayer;
Display theDisplay ;
int main ( int argc, char **argv )
{
playButton.attach ( boost::bind ( &Player::play, &thePlayer ) );
playButton.attach ( boost::bind ( &Display::started, &theDisplay ) );
stopButton.attach ( boost::bind ( &Player::stop, &thePlayer ) );
playButton.onClick() ;
stopButton.onClick() ;
return 0;
}
因此,当您运行它时,您会得到:
play
Started playing
stop
Press any key to continue.
所以..这是你要找的那种东西吗?
编辑: boost::signal 库也可能做你想做的事。
于 2009-03-05T11:56:27.653 回答
2
你为什么不只实施一个?这不是一个复杂的模式(好吧,取决于你真正想要的)。无论如何,我前段时间已经实现了一个快速而肮脏的。它没有经过优化、同步和单线程。我希望你可以用它来制作你自己的。
#include <vector>
#include <iostream>
#include <algorithm>
template<typename MESSAGE> class Topic;
class Subscriber;
class TopicBase
{
friend class Subscriber;
private:
virtual void RemoveSubscriber(Subscriber* subscriber)=0;
};
template<typename MESSAGE>
class Topic : public TopicBase
{
friend class Subscriber;
private:
class Callable
{
public:
Callable(Subscriber* subscriber, void (Subscriber::*method)(const MESSAGE&))
:m_subscriber(subscriber)
,m_method(method)
{
}
void operator()(const MESSAGE& message)
{
(m_subscriber->*m_method)(message);
}
bool operator==(const Callable& other) const
{
return m_subscriber == other.m_subscriber && m_method == other.m_method;
}
public:
Subscriber* m_subscriber;
void (Subscriber::*m_method)(const MESSAGE&);
};
public:
~Topic()
{
//unregister each subscriber
for(std::vector<Callable>::iterator i = m_subscribers.begin(); i != m_subscribers.end(); i++)
{
std::vector<TopicBase*>& topics = i->m_subscriber->m_topics;
for(std::vector<TopicBase*>::iterator ti = topics.begin();;)
{
ti = std::find(ti, topics.end(), this);
if(ti == topics.end()) break;
ti = topics.erase(ti);
}
}
}
void SendMessage(const MESSAGE& message)
{
for(std::vector<Callable>::iterator i = m_subscribers.begin(); i != m_subscribers.end(); i++)
{
(*i)(message);
}
}
private:
void Subscribe(Subscriber* subscriber, void (Subscriber::*method)(const MESSAGE&))
{
m_subscribers.push_back(Callable(subscriber, method));
subscriber->m_topics.push_back(this);
}
void Unsubscribe(Subscriber* subscriber, void (Subscriber::*method)(const MESSAGE&))
{
std::vector<Callable>::iterator i = std::find(m_subscribers.begin(), m_subscribers.end(), Callable(subscriber, method));
if(i != m_subscribers.end())
{
m_subscribers.erase(i);
subscriber->m_topics.erase(std::find(subscriber->m_topics.begin(), subscriber->m_topics.end(), this)); //should always find one
}
}
virtual void RemoveSubscriber(Subscriber* subscriber)
{
for(std::vector<Callable>::iterator i = m_subscribers.begin() ; i != m_subscribers.end(); i++)
{
if(i->m_subscriber == subscriber)
{
m_subscribers.erase(i);
break;
}
}
}
private:
std::vector<Callable> m_subscribers;
};
class Subscriber
{
template<typename T> friend class Topic;
public:
~Subscriber()
{
for(std::vector<TopicBase*>::iterator i = m_topics.begin(); i !=m_topics.end(); i++)
{
(*i)->RemoveSubscriber(this);
}
}
protected:
template<typename MESSAGE, typename SUBSCRIBER>
void Subscribe(Topic<MESSAGE>& topic, void (SUBSCRIBER::*method)(const MESSAGE&))
{
topic.Subscribe(this, static_cast<void (Subscriber::*)(const MESSAGE&)>(method));
}
template<typename MESSAGE, typename SUBSCRIBER>
void Unsubscribe(Topic<MESSAGE>& topic, void (SUBSCRIBER::*method)(const MESSAGE&))
{
topic.Unsubscribe(this, static_cast<void (Subscriber::*)(const MESSAGE&)>(method));
}
private:
std::vector<TopicBase*> m_topics;
};
// Test
Topic<int> Topic1;
class TestSubscriber1 : public Subscriber
{
public:
TestSubscriber1()
{
Subscribe(Topic1, &TestSubscriber1::onTopic1);
}
private:
void onTopic1(const int& message)
{
std::cout<<"TestSubscriber1::onTopic1 "<<message<<std::endl;
}
};
class TestSubscriber2 : public Subscriber
{
public:
void Subscribe(Topic<const char*> &subscriber)
{
Subscriber::Subscribe(subscriber, &TestSubscriber2::onTopic);
}
void Unsubscribe(Topic<const char*> &subscriber)
{
Subscriber::Unsubscribe(subscriber, &TestSubscriber2::onTopic);
}
private:
void onTopic(const char* const& message)
{
std::cout<<"TestSubscriber1::onTopic1 "<<message<<std::endl;
}
};
int main()
{
Topic<const char*>* topic2 = new Topic<const char*>();
{
TestSubscriber1 testSubscriber1;
Topic1.SendMessage(42);
Topic1.SendMessage(5);
}
Topic1.SendMessage(256);
TestSubscriber2 testSubscriber2;
testSubscriber2.Subscribe(*topic2);
topic2->SendMessage("owl");
testSubscriber2.Unsubscribe(*topic2);
topic2->SendMessage("owl");
testSubscriber2.Subscribe(*topic2);
delete topic2;
return 0;
}
于 2009-03-06T18:20:00.687 回答