网上介绍Boost signal原理的文章很多,这里不介绍原理,仅贴一些示例代码,这在初步接触Boost signal时能够有个较好的感性认识,深入了解需要去体会挖掘boost源码。代码基本上来自Boost turioal,其中有一些错误会导致编译不过,这里都做了更正:
1. 基本运用
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include <iostream>
using namespace std;
using namespace boost;
struct HelloWorld
{
void operator()() const
{
std::cout << "Hello, World!" << std::endl;
}
};
struct HelloKitty
{
void operator()() const
{
std::cout << "Hello, Kitty!" << std::endl;
}
};
//
struct GoodMorning
{
void operator()() const
{
std::cout << "... and good morning!" << std::endl;
}
};
class Hello
{
public:
void print()
{
std::cout << "Hello, World!" << std::endl;
}
};
class World : public boost::signals2::trackable
{
public:
void print()
{
std::cout << "Hello, World!" << std::endl;
}
};
void print_hello()
{
std::cout<<"Hello, world"<<std::endl;
}
void print_sum(float x, float y)
{
std::cout << "The sum is " << x+y << std::endl;
}
void print_product(float x, float y)
{
std::cout << "The product is " << x*y << std::endl;
}
void print_difference(float x, float y)
{
std::cout << "The difference is " << x-y << std::endl;
}
void print_quotient(float x, float y)
{
std::cout << "The quotient is " << x/y << std::endl;
}
float product(float x, float y) { return x*y; }
float quotient(float x, float y) { return x/y; }
float sum(float x, float y) { return x+y; }
float difference(float x, float y) { return x-y; }
template<typename T>
struct maximum
{
typedef T result_type;
template<typename InputIterator>
T operator()(InputIterator first, InputIterator last) const
{
// If there are no slots to call, just return the
// default-constructed value
if (first == last)
return T();
T max_value = *first++;
while (first != last) {
if (max_value < *first)
max_value = *first;
++first;
}
return max_value;
}
};
template<typename Container>
struct aggregate_values
{
typedef Container result_type;
template<typename InputIterator>
Container operator()(InputIterator first, InputIterator last) const
{
return Container(first, last);
}
};
// Signal with no arguments and a void return value
int main()
{
// Connect a HelloWorld slot
HelloWorld hello;
HelloKitty kitty;
GoodMorning goodMorning;
std::cout<<"****************sig1******************"<<std::endl;
boost::signals2::signal<void ()> sig1;
sig1.connect(1 ,hello);
sig1.connect(0 ,kitty);
sig1.connect(0 ,goodMorning);
sig1();
// Call all of the slots
std::cout<<"****************sig2******************"<<std::endl;
boost::signals2::signal<void (float, float) > sig2;
sig2.connect(&print_product);
sig2.connect(&print_quotient);
sig2.connect(&print_sum);
sig2.connect(&print_difference);
sig2(5, 3);
std::cout<<"****************sig3*******************"<<std::endl;
boost::signals2::signal<float (float, float) > sig3;
sig3.connect(product);
sig3.connect(quotient);
sig3.connect(sum);
sig3.connect(difference);
std::cout<< *sig3(5,3)<<std::endl;
std::cout<<"****************sig4*******************"<<std::endl;
boost::signals2::signal<float (float, float), maximum<float> > sig4;
sig4.connect(product);
sig4.connect(quotient);
sig4.connect(sum);
sig4.connect(difference);
std::cout<< sig4(5,3)<<std::endl;
std::cout<<"****************sig5*******************"<<std::endl;
boost::signals2::signal<float (float, float), aggregate_values<std::vector<float> > > sig5;
sig5.connect(product);
sig5.connect(quotient);
sig5.connect(sum);
sig5.connect(difference);
std::vector<float> results = sig5(5, 3);
std::copy(results.begin(), results.end(), std::ostream_iterator<float>(cout, "\n"));
std::cout<<"***************connection management connected**************"<<std::endl;
boost::signals2::signal<void ()> sig6;
boost::signals2::connection c = sig6.connect(HelloWorld());
if (c.connected())
{
// c is still connected to the signal
sig6(); // Prints "Hello, World!"
}
c.disconnect(); // Disconnect the HelloWorld object
assert(!c.connected());
sig6(); // Does nothing: there are no connected slots
std::cout<<"***************connection management block**************"<<std::endl;
boost::signals2::signal<void ()> sig7;
boost::signals2::connection c1 = sig7.connect(HelloWorld());
sig7();
{
boost::signals2::shared_connection_block block(c1);
sig7();
std::cout<<"c1 is blocked"<<std::endl;
}
assert(!c1.blocked());
sig7();
std::cout<<"***************connection management scoped**************"<<std::endl;
boost::signals2::signal<void ()> sig8;
{
boost::signals2::scoped_connection c2(sig8.connect(HelloWorld()));
sig8();
std::cout<<"c2 is blocked"<<std::endl;
}
sig8();
std::cout<<"***************connection management connected**************"<<std::endl;
boost::signals2::signal<void ()> sig9;
sig9.connect(print_hello);
sig9();
std::cout<<"Disconnected sig9"<<std::endl;
sig9.disconnect(print_hello);
sig9();
std::cout<<"***************connection management use shared_ptr**************"<<std::endl;
boost::signals2::signal<void ()> sig10;
{
boost::shared_ptr<Hello> w(new Hello());
sig10.connect(boost::bind(&Hello::print, w.get()));
}
std::cout <<"num of slots = "<< sig10.num_slots() << std::endl;
sig10();
std::cout<<"***************connection management use trackable**************"<<std::endl;
boost::signals2::signal<void ()> sig11;
{
boost::shared_ptr<World> w(new World());
sig11.connect(boost::bind(&World::print, w.get()));
}
std::cout <<"num of slots = "<< sig11.num_slots() << std::endl;
sig11();
return 0;
}
2. 综合运用
#include <iostream>
#include <string>
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
class NewsItem
{
public:
NewsItem();
NewsItem(const NewsItem& item)
{
msg = item.msg;
}
NewsItem(const std::string message)
{
msg = message;
}
const std::string text() const
{
return msg;
}
private:
std::string msg;
};
class MessageArea
{
public:
MessageArea(){messageText = "default";}
MessageArea(const MessageArea& messageArea)
{
messageText = messageArea.messageText;
}
MessageArea(const std::string message)
{
messageText = message;
}
void update()
{
std::cout <<"messageText="<<messageText<<std::endl;
}
std::string messageText;
};
class NewsMessageArea : public MessageArea, public boost::signals2::trackable//trackable is important
{
public:
NewsMessageArea(const std::string message):MessageArea(message){}
void displayNews(const NewsItem& news)
{
messageText = news.text();
update();
}
};
int main()
{
boost::signals2::signal<void (const NewsItem&) > deliverNews;
NewsMessageArea* newsMessageArea = new NewsMessageArea("Hello, World!");
deliverNews.connect(boost::bind(&NewsMessageArea::displayNews, newsMessageArea, _1));
const NewsItem newItem("Hello, Kitty!");
deliverNews(newItem);
delete newsMessageArea;
std::cout<<"*******Segmentation fault below if no trackable******"<<std::endl;
deliverNews(newItem);
return 0;
}
3. Boost Signal 运用于Documnet-View 模式
#include <iostream>
#include <string>
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
class Document
{
public:
typedef boost::signals2::signal<void (bool)> signal_t;
typedef boost::signals2::connection connection_t;
public:
Document()
{}
connection_t connect(signal_t::slot_function_type subscriber)
{
return m_sig.connect(subscriber);
}
void disconnect(connection_t subscriber)
{
subscriber.disconnect();
}
void append(const char* s)
{
m_text += s;
m_sig(true);
}
const std::string& getText() const
{
return m_text;
}
private:
signal_t m_sig;
std::string m_text;
};
class View
{
public:
View(Document& m)
: m_document(m)
{
m_connection = m_document.connect(boost::bind(&View::refresh, this, _1));
}
virtual ~View()
{
m_document.disconnect(m_connection);
}
virtual void refresh(bool bExtended) const = 0;
protected:
Document& m_document;
private:
Document::connection_t m_connection;
};
class TextView : public View
{
public:
TextView(Document& doc)
: View(doc)
{}
virtual void refresh(bool bExtended) const
{
std::cout << "TextView: " << m_document.getText() << std::endl;
}
};
class HexView : public View
{
public:
HexView(Document& doc)
: View(doc)
{}
virtual void refresh(bool bExtended) const
{
const std::string& s = m_document.getText();
std::cout << "HexView:";
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it)
std::cout << ' ' << std::hex << static_cast<int>(*it);
std::cout << std::endl;
}
};
int main(int argc, char* argv[])
{
Document doc;
TextView v1(doc);
HexView v2(doc);
doc.append(argc == 2 ? argv[1] : "Hello world!");
return 0;
}
另外这篇文章队Boost Signal的trackable特性有较为深入的分析,推荐大家可以参考下