和大家说了这么久的boost内容,嗯,可能现在有些同学还是不明白boost是什么,好吧,如果还有人没有安装了boost的话,那么我这里给大家提供一个版本,这也是我最近一直在使用的版本,boost_1_56的,但是是在vs2013下面编译的,如果不是使用vs2013的编译器的话,那么该版本不适合你们,如果大家想要自己编译的话也是ok的了,
这是我使用的版本,大家可以在网盘里面下载,下载下来解压出来既可以:
http://yun.baidu.com/share/link?shareid=268236972&
uk=2114708594
下面为还不会使用boost的同学做一些介绍,主要针对VS2013和Qt:
Qt:
//—————————————————–
INCLUDEPATH += ../../../vslib/boost_2013/include
QMAKE_INCDIR += ../../../vslib/boost_2013/include
QMAKE_LIBDIR += ../../../vslib/boost_2013/lib
//——————————————————
Qt下面就是这么简单,INCLUDEPATH ,QMAKE_INCDIR ,QMAKE_LIBDIR 三个命令就可以,../../../vslib/boost_2013/include可以是绝对路径也可以是相对路径,该例子里面使用的是相对路径。
和Qt比起,VS相对来说步骤要多一些,但更为直接一些,步骤如下:
1.选中我们的工程
2.在菜单栏中找到项目,点击项目,找到最后一项属性,点击进去。
3.在左边的导航栏中找到C/C++ —>常规
4.在常规对应的界面里找到第一项(附加包含目录),在后面的下拉框中点击向下的三角形,点击编辑,然后将我们的需要包含的包含的路径写进去就可以。
5.添加了附加包含目录后还需要添加lib路径,这时在左边导航栏找到链接器—>常规,找到附加库目录,和添加附加包含目录一样将lib所在的路径添加在此处即可
最后点击应用确定就ok。
好了,那么今天我们来使用上一讲中我们谈到的signal和slot来实现一个观察者模型的小例子:
//——————————————-
// 场景:
//——————————————-
某人给张三打了个电话,张三可能听见电话并且接了电话了,当然张三可能没有听见电话,但是他的同学李四听见张三的电话响了,于是告诉张三,张三接电话,当然也有可能两人都没有听见电话。
这样的场景在我们现实生活中比比皆是,也是观察者模式的典型范例,如果我们用程序来模拟这个场景的话,加入我们没有signal这个东西可能会显得相对麻烦一些,那么,现在我们拥有signal这个东西,所以模拟起来就相对简单了。
//——————————————–
// 首先我们来实现一个电话的类
//——————————————–
class Phone{
typedef boost::signals2::signal<void(std::string)>signal_type;
typedef signal_type::slot_type slot_type;
public:
boost::signals2::connection connect(const slot_type&
slot){
return mCall.connect(slot);
}
void Called(const std::string&
oher){
std::cout <<"
have a phone … "
<<std::endl;
mCall(oher);
}
private:
signal_type mCall;
};
//—————————————–
// 接下来我们实现一个同学类
//—————————————–
mj::GenRandom<int>
m_gen(0, 100);
template<const char* name>
class Schoolmate{
typedef boost::signals2::signal<void(std::string)>signal_type;
typedef signal_type::slot_type slot_type;
public:
std::string Name(){
return name;
}
//—————————————–
// 一个操作函数
//—————————————–
void Action1(const std::string&
__name){
m_name = __name;
int
num = m_gen();
if (num >30){
b_is_connect = true;
if (__name != name){
Notice();
return;
}
std::cout <<name <<"
: Hello , this is "
<<name <<std::endl;
}
else{
b_is_connect = false;
}
}
void Action2(const std::string&
__name){
if (name != __name)
return;
if (b_is_connect){
return;
}
else{
std::cout <<name <<"
: oh! thank you … "
<<std::endl;
}
}
//———————————–
// 通知一下其他人
//———————————–
void Notice(){
std::cout <<name <<"
: "
<<m_name <<"
, "
<<"
your have a phone … "
<<std::endl;
m_sig(m_name);
}
boost::signals2::connection connect(slot_type slot){
return m_sig.connect(slot);
}
private:
std::string m_name;
bool b_is_connect{ false
};
signal_type m_sig;
};
嗯,这个同学类是一个模板类,模板参数是一个const char*的东西,关于指针和引用作为模板参数的一些模板高级知识如果大家没有印象的话可以回去看看大概是第九十多讲的地方,那里说了一些关于模板的高级知识,这里再给大家提醒一下:引用和指针模板参数必须引用能够在所有编译单元内访问的全局变量,然而,用于描述这些类型的变量的技术术语是:带有外部链接的数据,也就是说我们在声明这些全局变量时需要指明为extern。
再说说这个同学类,这个类不但可以提供外部的slot,还能够自己观察自己,Atction2这个函数我们就是提供来给自己观察自己使用的。
好了,再来看看一个打电话的类:
class Caller{
public:
void call(Phone&
phone,const std::string&
oher){
phone.Called(oher);
}
};
//————————————–
// 现在声明两个具有外部链接属性的指针
//————————————–
extern const char ZhangSan[] = "
Zhang san"
;
extern const char LiSi[] = "
LiSi"
;
int main(){
Phone p;
Schoolmate<ZhangSan>mate1;
Schoolmate<LiSi>mate2;
p.connect(std::bind(&
Schoolmate<ZhangSan>::Action1, &
mate1,std::placeholders::_1));
p.connect(std::bind(&
Schoolmate<LiSi>::Action1,&
mate2, std::placeholders::_1));
//————————————–
// 同学之间的相互观察
//————————————–
mate2.connect(std::bind(&
Schoolmate<ZhangSan>::Action2, &
mate1, std::placeholders::_1));
mate1.connect(std::bind(&
Schoolmate<LiSi>::Action2, &
mate2, std::placeholders::_1));
Caller c;
c.call(p, ZhangSan);
return 0;
}
现在我们来运行程序,我们会发现有不同的结果:
ok,关于Signal就说到这里吧,如果大家有什么疑问可以向我提出,可以这里提问,同时也可以添加我的微信进行提问:我的微信号:mengjin3771
//—————————————
回复D或者d可以查看目录,回复数字查看相应的章节
原文始发于微信公众号(
C/C++的编程教室
):第111讲 使用信号实现观察者模式
|