C++中std::tr1::function和bind 组件的使用

在C++的TR1中(Technology Report)中包含一个function模板类和bind模板函数,使用它们可以实现类似函数指针的功能,但却却比函数指针更加灵活,特别是函数指向类的非静态成员函数时。可以参考Scott Meyers. <<Effective C++ (3rd Edition)>>. Item 35.下面具体说明其使用方法。

一、指向全局函数或静态成员函数时

因为在本质上讲全局函数和静态成员函数没有区别,使用方法上除了静态成员函数在引用时要在前面加域作用符className::外,没有其它任何区别,事实上全局函数也有可能放入命名空间,或者使用全局域作用符,例如 nameSpace::function() 或::function,这样不仅本质上相同,形势上也与静态成员函数一致了,所以它们是没有区别的,放到一起讨论。

这种情况比较简单,只需要定义一个类型

#include <iostream>

#include <iomanip>

#include <tr1/memory>

#include <tr1/functional>

typedef   std::tr1::function<void (int)>   HandlerEvent;

然后再定义一个成员变量

class Sharp{

public:

    HandlerEvent handlerEvent;

};

然后在其它函数内就可以通过设置handlerEvent的值来动态装载事件响应函数了,如:

class Rectangle{

private:

    std::string name;

    Sharp sharp;

public:

    void initial(void);

    const Sharp getSharp() const;

    static void onEvent(int param){  //---------------(1)

        std::cout << "invode onEvent method,get parameter: " << param << std::endl;

    }

};

//类的实现方法

void Rectangle::initial(){

    sharp.handlerEvent = HandlerEvent(&Rectangle::onEvent); //---------------(2)

    std::cout << "invode initial function!" << std::endl;

}

const Sharp Rectangle::getSharp() const{

    return sharp;

}

//下面为测试函数:

int main(int argc,char *argv[]){

    std::cout <<"hi: " << std::setw(50) << "hello world!" << std::endl;

    Rectangle rectangle;

    rectangle.initial();  //---------------(3)

    rectangle.getSharp().handlerEvent(23);    //---------------(4)

}

//输出结果如下:

hi:                                       hello world!

invode initial function!

invode onEvent method,get parameter: 23    //---------------(5)

 

注意,这里使用了静态成员函数,如果把Rectangle前面的static去掉这段代码不能工作,编译都不能通过,因为静态成员函数与非静态成员函数的参数表不一样,原型相同的非静态函数比静态成员函数多一个参数,即第一个参数this指针,指向所属的对象,任何非静态成员函数的第一个参数都是this指针,所以如果把Rectangle前面的static去掉,其函数原型等效于下面的一个全局函数:

void onEvent(Rectangle* this, int);

所以,这与HandlerEvent所声明的函数类型不匹配,编译将不能通过。而且,既然静态成员函数没有this指针,所以上面(3)处的调用使sharp对象中的handlerEvent使向了Rectangle的静态方法onEvent(),这样当通过(4)处这样调用时就会自动执行(1)处的静态函数onEvent()。

二、std::tr1::bind()模板函数的使用

通过上面的std::tr1::function 可以对静态成员函数进行绑定,但如果要对非静态成员函数的绑定,需用到下机将要介绍的bind()模板函数.

首先说bind的用法,其声明如下所示:

    bind(Function fn, T1 t1, T2 t2, …, TN tN);

其中fn为将被调用的函数,t1…tN为函数的参数。如果不指明参数,则可以使用占位符表示形参,点位符格式为

std::tr1::placehoders::_1,  std::tr1::placehoders::_2,  …,  std::tr1::placehoders::_N

将上例中Rectangle::onEvent(int param)前的static去掉改为非静态成员函数,则进行动态绑定使得程序正常运行,将Rectangle::initial(void)的定义修改为:

void Rectangle::initial(){

    sharp.handlerEvent = std::tr1::bind(&Rectangle::onEvent,this,std::tr1::placeholders::_1/*因onEvent函数需要一个参数,所以用一占位符*/);

    std::cout << "invode initial function!" << std::endl;

}

这样,便动态装载函数成功。其它测试数据都不用进行修改。测试结果于上一样。

三、指向虚成员函数的使用

对于虚成员函数的情况与上面第2节所说相同,仍然可以实现虑函数的效果。如果定义类Square继承自Rectangle,将Rectangle::OnEvent重载,定义一个新的Square::OnEvent,Rectangle::initialize中的函数不变,仍然使用Rectangle::OnEvent进进绑定,则调用成员object.onEvent()时,具体执行Rectangle::OnEvent还是Square::OnEvent,看object所属对象的静态类型是Rectangle还是Square而定.

下面为简单示例:

我们首先修改一个上面Rectangle的initial()方法,改为虚函数。如:

 virtual void onEvent(int param){

        std::cout << "invode Rectangle's onEvent method,get parameter: " << param << std::endl;

    }

然后我们再写一个Square类来继承Rectangle类。并重写onEvent方法。如:

class Square : public Rectangle{

public:

void onEvent(int param){

        std::cout << "invode Square's onEvent method,get parameter: " << param << std::endl;

    }

};

测试代码:

int main(int argc,char *argv[]){

    Rectangle rectangle;

    rectangle.initial();

    rectangle.getSharp().handlerEvent(23);

    Square square;

    square.initial();

    square.getSharp().handlerEvent(33);

}

运行后的结果如下:

hi:                                       hello world!

invode initial function!

invode Rectangle's onEvent method,get parameter: 23

invode initial function!

invode Square's onEvent method,get parameter: 33

这样我们就可以看到sharp会针对具体对象来调用相应的onEvent()方法。 上面的程序示例读者可自行研习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/433580.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux(centos7)安装MySQL

一、删除MariaDB的文件 通过命令查询MariaDB&#xff1a;rpm -pa | grep mariadb 通过命令删除查找到的程序rpm -e 查找到的文件名 如果删除失败&#xff0c;就通过下面的命令强制删除&#xff1a;rpm -e --nodeps 查找到的文件名 二、安装MySQL 1、安装mysql repo源 …

python ddos攻击脚本_python版本DDOS攻击脚本

今天为了休息下&#xff0c;换换脑子&#xff0c;于是就找到了我之前收藏的一篇python的文章&#xff0c;是关于ddos攻击的一个脚本&#xff0c;正好今天有空&#xff0c;就实践下了。 附上源码pyDdos.py:#!/usr/bin/env python import socket import time import threading #P…

设计模式 - Command

意图&#xff1a;将一个请求封装为一个对象&#xff0c;从而使你可用不同的请求对客户进行参数化&#xff1b;对请求排队或记录请求日志&#xff0c;以及支持可撤消的操作。 class Receiver { public:Receiver(){}virtual ~Receiver(){}virtual void Action(){cout<<&quo…

代码中特殊的注释技术——TODO、FIXME和XXX的用处

前言&#xff1a;今天在阅读Qt Creator的源代码时&#xff0c;发现一些注释中有FIXME英文单词&#xff0c;用英文词典居然查不到其意义&#xff01;实际上&#xff0c;在阅读一些开源代码时&#xff0c;我们常会碰到诸如&#xff1a;TODO、FIXME和XXX的单词&#xff0c;它们是…

我有机器人合体成一个大力神_史上最菜大力神(三)——SS加强级高塔

史上最菜大力神&#xff08;三&#xff09;——SS加强级高塔​mp.weixin.qq.com上次开箱废渣和狂暴的时候&#xff0c;误把电影中出现的高塔当作废渣&#xff0c;犯下了一个不大不小的错误&#xff0c;如今真正的高塔终于来了。史上最菜大力神&#xff08;一&#xff09;——SS…

c语言判断闰年_C语言1博客作业06 - D丶千思

1.作业头实验作业输入在一行中按照格式“yyyy/mm/dd”(即“年/月/日”)给出日期。注意&#xff1a;闰年的判别条件是该年年份能被4整除但不能被100整除、或者能被400整除。闰年的2月有29天。.1数据处理数据表达&#xff1a;采用整形定义变量Y(year)&#xff0c;M(month)&#x…

新版本idea的run/debug configuration

点击Edit Configuration点击modify options的下拉选项根据需要勾选相应的选项

登录用户Eclipse中SVN访问用户的变更办法

废话就不多说了&#xff0c;开始。。。 有点标题党了&#xff0c;呵呵 其实不止Eclipse成集SVN&#xff0c;全部SVN拜访用户的更变&#xff0c;都可以参照面下的式方 每日一道理 谁说人与人隔着遥远的重洋&#xff0c;谁说心与心设着坚固的堤防&#xff1f;十六岁的鸟儿飞上天空…

无法渲染窗口发黄_基础c4d教程:OC渲染器的立体光照

一、效果图昨天才把C4DR19安装好&#xff0c;之前安装一直在说无法找到系统的什么dll&#xff0c;后面查了好多方法终于弄好了&#xff0c;今天我也是第一次使用OC渲染&#xff0c;所以可能调节就没有那么好&#xff0c;大家一起进步吧&#xff01;二、教程1、首先打开我们的C4…

java8 list 去重_Java8-Stream在集合中的8种应用案例

前言Java8新特性我们使用的应该比较多了&#xff0c;今天这里整理了个人使用最多的8种场景&#xff0c;希望对大家有所帮助。Java Stream在集合中的运用案例遍历遍历也许是我们使用最多的功能了&#xff0c;在Java8之前我们遍历集合通常会采用for循环&#xff0c;迭代器&#x…

springboot——热部署

一、手动启动热部署 在进行 Spring Boot 的 Web 项目开发中&#xff0c;我们经常会遇到源代码文件、 配置文件等的修改&#xff0c;但每次修改后都会重启 Web 服务器才能修改后的文件生效&#xff0c; 这样很耗时&#xff0c;影响开发效率。而热部署就是不需要重启 Web 服务器就…

(转载)ubuntu开启SSH服务

&#xff08;转载&#xff09; http://www.cnblogs.com/xiazh/archive/2010/08/13/1798844.htmlSSH分客户端openssh-client和openssh-server如果你只是想登陆别的机器的SSH只需要安装openssh-client&#xff08;ubuntu有默认安装&#xff0c;如果没有则sudo apt-get install op…

cmake 学习笔记(一)

最大的Qt4程序群(KDE4)采用cmake作为构建系统Qt4的python绑定(pyside)采用了cmake作为构建系统开源的图像处理库 opencv 采用cmake 作为构建系统... 看来不学习一下cmake是不行了&#xff0c;一点一点来吧&#xff0c;找个最简单的C程序&#xff0c;慢慢复杂化&#xff0c;试试…

c++邮递员投递经过特定点_厉害了斑马鱼,动物实验体天团C位

明明是一条鱼&#xff0c;为什么在保健食品以及药品领域即将成为实验动物C位&#xff1f;越来越多的药品及保健食品企业&#xff0c;都想邀请它们成为座上宾&#xff0c;是时候展示真正的技术了&#xff01;透明就是很厉害斑马鱼从胚胎阶段至未来的成熟阶段&#xff0c;身体中有…

选了combobox里的选项后没激发change事件_备胎测试:来测测你被备胎了没?

很多人在感情里被备胎而不自知&#xff0c;今天就来教大家如何辨别备胎。你知道备胎的最大特征是什么吗&#xff1f;是在面对关系定位时&#xff0c;态度上的模棱两可。想想你身边养备胎的人&#xff0c;如果没有的话&#xff0c;想想电视剧或小说里养备胎的人&#xff0c;想想…

第七章:清楚简洁的英文 --《英语科技写作(文法与修辞原则)》by 方克涛

1. 在英文写作中&#xff0c;最好的方法是效仿英文为母语的写作者。 2. 资深的英文写作者&#xff0c;都喜欢直接而间接的写作方式。在中文写作中&#xff0c;作者有时候会假定读者已经知道主语是谁而将其省略&#xff0c;而英文中主语是必须有的&#xff0c;不能省略。 7.1 句…

warning no newline at the end of file

main.c :10:2 warning: no newline at the end of file 修复这个警告&#xff0c;在文件结尾回车一下就行了。可以很少会有人去仔细探究&#xff0c;为什么gcc会给出这么一个警告&#xff1f; 原因其实也很简单&#xff0c;因为标准规定如此。C99第5.1.1.2节这样写道&#xff1…

halcon旋转后坐标_FPGA大赛【八】具体模块设计图像旋转方案

【注】该项目是我们团队参加2019届全国大学生FPGA大赛的作品&#xff0c;系统主要实现视频任意角度旋转。该项目最终晋级决赛&#xff0c;并获得紫光同创企业特别奖。该系列文章介绍我们团队的作品。关注公众号“数字积木”对话框回复 FPGA2019 &#xff0c;即可获得该项目的工…

python获取pid并杀死_用python记录运行pid,并在需要时kill掉它们的实例

我在跑爬虫程序的时候&#xff0c;由于爬虫程序的等待目标服务器返回数据的时间很长&#xff0c;而cpu占用很低&#xff0c;所以经常挂着代理一跑就跑好几百个。但是爬虫程序通常是写了死循环&#xff0c;或直到分配给该进程的任务都跑完才退出的。如果我们想中途结束掉这些任务…

ASP.NET 错误

用Visual Studio2008 启动调试时出现以下错误&#xff1a; configuring web site for asp.net failed you must manually configure this site..... 在IE中浏览网页时&#xff1a; 访问IIS元数据库失败 异常详细信息: System.Web.Hosting.HostingEnvironmentException: 访问 …