libsigc++库的使用

本文介绍了libsigc++库在C++中的应用,它提供了类型安全的信号与槽机制。文中详细讲解了如何创建槽,包括普通函数、函数对象和成员函数,并展示了如何连接信号和槽,以及如何断开连接。此外,还讨论了类型不匹配时的重绑定和类型重定义等高级话题。

Libsigc++库的使用

 

概述

通常在图形用户界面程序中,我们希望检测事件的代码与处理事件的代码能够分开独立出来。我们可以使用回调函数的机制,注册函数指针来注册相关的处理函数,不过,在C++中,我们可以使用类型安全的库libsigc++

 

Libsigc++库中提出了槽的概念,熟悉Qt的朋友应该对槽的概念不陌生,它其实是指向一个可作为回调的函数的引用,以下三种类型的函数都可作为槽:

1. 普通函数。

2. 重载了operator()的函数子对象(类)。

3. 如果对象所属的类继承了sigc::trackable, 它的成员函数也可以作为槽。

 

针对第三种类型的函数,libsigc++库提供了sigc::ptr_func()sigc::mem_func()为分别从类的静态函数和对象的成员函数中创建槽。返回值类型是signal::slot,可通过emit()operator()调用。另外,libsigc++也提出了信号的概念signals,它是模板类型sigc::signal实例, 可将信号与槽连接起来,当emit信号时,所有连接到信号的槽将会执行。

 

一个简单的示例

Signal发送方:

class AlienDetector

{

public:

    AlienDetector()

    {

    }

 

    void run()

    {

        cout<<"AlienDetector is running"<<endl;

//        signal_detected.emit();

        signal_detected();

    }

    sigc::signal<void> signal_detected;

};

 

槽函数定义,与信号的返回值类型一致:

void warn_people()

{

    cout<<"There are aliens in the carpark!"<<endl;

}

 

连接信号和槽:

int main()

{

    AlienDetector mydetector;

    mydetector.signal_detected.connect(sigc::ptr_fun(warn_people));

    mydetector.run();

 

    return 0;

}

 

头文件包含:

#include <iostream>

#include <sigc++/sigc++.h>

 

编译:

g++ example1.cc -o example1 `pkg-config --cflags --libs sigc++-2.0`

 

使用成员函数作为槽

上述例子演示了普通函数作为槽函数,接下来的例子将显示如何将成员函数作为槽使用。

提供槽函数的类定义如下,必须从sigc::trackable继承:

class AlienAlerter : public sigc::trackable

{

public:

    AlienAlerter(char const* servername)

    {

        srvname = string(servername);

    }

 

    void alert()

    {

cout<<"server name: "<<srvname<<endl;

    }

private:

    // ...

    string srvname;

};

连接信号和槽

int main()

{

    AlienDetector mydetector;

    AlienAlerter  myalerter("localhost");

    mydetector.signal_detected.connect(sigc::mem_fun(myalerter, &AlienAlerter::alert));

    mydetector.run();

 

    return 0;

}

 

带参数的信号

信号的类型sigc::signal的模板参数中第一个是返回值类型,后面都是信号参数的类型,如:

sigc::signal<void, std::string>

那么对应的槽函数声明也必须为返回值为void, 接受一个参数为std::string的函数,即:

void warn_people(std::string where)

{

    cout << "There are aliens in " << where << "!" << endl;

}

如前述AlienDetector类的声明修改如下:

class AlienDetector

{

public:

    AlienDetector();

 

    void run();

 

    sigc::signal<void, std::string> signal_detected; // changed

};

 

连接信号和槽:

int main()

{

    AlienDetector mydetector;

    mydetector.signal_detected.connect( sigc::ptr_fun(warn_people) );

 

    mydetector.run();

 

    return 0;

}

 

断开信号和槽之间的连接

信号sigc::signalconnect方法的返回值类型为:sigc::connection, 它提供了一个disconnect函数来断开信号和槽之间的连接。

 

高级话题

重新绑定(rebinding)

当信号与槽的类型不匹配时,连接时会出现编译错误。为了解决这种不匹配的情况,我们可以利用sigc::bind进行重绑定,便信号与槽之间的类型能够重新匹配。

假设我们定义了除返回值外, 不带任何参数的信号,这样与之连接的槽函数也不能接受任何参数。如果我们要利用一个已经写好的并需要传入参数的函数,我们可以通过sigc::bind作些处理,如下所示:

myaliendetector.signal_detected.connect(sigc::bind( sigc::ptr_fun(warn_people), "the carpark" ) );

其中sigc::bind(slot, arg), 如果槽函数接受多个参数,那么arg指的是最右边那个参数。

另外,返回值的类型也可以通过类似的方式重新绑定:

sigc::bind_return(slot, returnvalue)

 

反过来,如果我们要利用一个已存在的函数作为槽函数,它接受一个参数,但是信号要求槽函数不接受任何参数,可以通过如下方式进行重新绑定:

myaliendetector.signal_detected.connect( sigc::hide<std::string>( sigc::ptr_fun(warn_people) ) );

,如果有多个参数,如上写法隐藏的是最右边的参数。

 

类型重定义(Retyping)

另一种情况是,当信号接受一个整型参数,但我们想让它与一个接受双精度类型的槽函数连接,这时需要进行类型重定义,可以通过sigc::retype模板类型,它与sigc::signal的模板参数一样。

void dostuff(double foo)

{

}

 

sigc::signal<void,int> asignal;

 

asignal.connect(  sigc::retype<void, int>( slot(&dostuff) )  );

当只是返回类型不同时,则只需指定返回类型参数。

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值