function模板类和bind模板函数,使用它们可以实现类似函数指针的功能,但却却比函数指针更加灵活,特别是函数指向类 的非静态成员函数时。
std::function可以绑定到全局函数/类静态成员函数(类静态成员函数与全局函数没有区别),如果要绑定到类的非静态成员函数,则需要使用std
从最基础的了解,std::bind和std::function
- /*
- * File: main.cpp
- * Author: Vicky.H
- * Email: eclipser@163.com
- */
- #include <iostream>
- #include <functional>
- #include <typeinfo>
- #include <string.h>
- int add1(int i,int j,int k) {
- return i + j + k;
- }
- class Utils {
- public:
- Utils(const char* name) {
- strcpy(_name, name);
- }
- void sayHello(constchar* name)const {
- std::cout << _name << " say: hello " << name << std::endl;
- }
- static int getId() {
- return 10001;
- }
- int operator()(int i,int j,int k)const {
- return i + j + k;
- }
- private:
- char _name[32];
- };
- /*
- *
- */
- int main(void) {
- // 绑定全局函数
- auto add2 = std::bind(add1, std::placeholders::_1, std::placeholders::_2, 10);
- // 函数add2 = 绑定add1函数,参数1不变,参数2不变,参数3固定为10.
- std::cout << typeid(add2).name() << std::endl;
- std::cout << "add2(1,2) = " << add2(1, 2) << std::endl;
- std::cout << "\n---------------------------" << std::endl;
- // 绑定成员函数
- Utils utils("Vicky");
- auto sayHello = std::bind(&Utils::sayHello, utils/*调用者*/, std::placeholders::_1/*参数1*/);
- sayHello("Jack");
- auto sayHelloToLucy = std::bind(&Utils::sayHello, utils/*调用者*/,"Lucy"/*固定参数1*/);
- sayHelloToLucy();
- // 绑定静态成员函数
- auto getId = std::bind(&Utils::getId);
- std::cout << getId() << std::endl;
- std::cout << "\n---------------------------" << std::endl;
- // 绑定operator函数
- auto add100 = std::bind(&Utils::operator (), utils, std::placeholders::_1, std::placeholders::_2, 100);
- std::cout << "add100(1, 2) = " << add100(1, 2) << std::endl;
- // 注意:无法使用std::bind()绑定一个重载函数
- return 0;
- }
/*
* File: main.cpp
* Author: Vicky.H
* Email: eclipser@163.com
*/
#include <iostream>
#include <functional>
#include <typeinfo>
#include <string.h>
int add1(int i, int j, int k) {
return i + j + k;
}
class Utils {
public:
Utils(const char* name) {
strcpy(_name, name);
}
void sayHello(const char* name) const {
std::cout << _name << " say: hello " << name << std::endl;
}
static int getId() {
return 10001;
}
int operator()(int i, int j, int k) const {
return i + j + k;
}
private:
char _name[32];
};
/*
*
*/
int main(void) {
// 绑定全局函数
auto add2 = std::bind(add1, std::placeholders::_1, std::placeholders::_2, 10);
// 函数add2 = 绑定add1函数,参数1不变,参数2不变,参数3固定为10.
std::cout << typeid(add2).name() << std::endl;
std::cout << "add2(1,2) = " << add2(1, 2) << std::endl;
std::cout << "\n---------------------------" << std::endl;
// 绑定成员函数
Utils utils("Vicky");
auto sayHello = std::bind(&Utils::sayHello, utils/*调用者*/, std::placeholders::_1/*参数1*/);
sayHello("Jack");
auto sayHelloToLucy = std::bind(&Utils::sayHello, utils/*调用者*/, "Lucy"/*固定参数1*/);
sayHelloToLucy();
// 绑定静态成员函数
auto getId = std::bind(&Utils::getId);
std::cout << getId() << std::endl;
std::cout << "\n---------------------------" << std::endl;
// 绑定operator函数
auto add100 = std::bind(&Utils::operator (), utils, std::placeholders::_1, std::placeholders::_2, 100);
std::cout << "add100(1, 2) = " << add100(1, 2) << std::endl;
// 注意:无法使用std::bind()绑定一个重载函数
return 0;
}
二、cocos2dx 3.0对std::bind运用
auto closeItem = MenuItemImage::create(s_pathClose, s_pathClose,std::bind(&HelloWorld::closeCallback,this));
void HelloWorld::closeCallback(Ref * sender)
{
exit(0);
}
其中std::bind(&HelloWorld::closeCallback,this)可以用cocos2dx-3.0中定义的宏来替换例如:
CC_CALLBACK_1(TestController::closeCallback, this)
小小的总结下:CC_CALLBACK0是回调不带参数的回调函数,CC_CALLBACK1带一个参数的回调命名空间基础
namespace 关键字使得我们可以通过创建作用范围来对全局命名空间进行分隔。本质上来讲,一个命名空间就定义了一个范围。定义命名空间的基本形式如下:
namespace名称{//声明}
在命名空间中定义的任何东西都局限于该命名空间内。
下面就是一个命名空间的例子,其中对一个实现简单递减计数器的类进行了本地化。在该命名空间中定义了计数器类用来实现计数;其中的upperbound和lowerbound用来表示计数器的上界和下界。
演示命名空间
- namespace CounterNameSpace
- {
- int upperbound;
- int lowerbound;
- class counter
- {
- int count;
- public:
- counter(int n)
- {
- if ( n<= upperbound){
- count = n;
- } else {
- count = upperbound;
- }
- }
- void reset(int n)
- {
- if ( n< upperbound)
- {
- count = n;
- }
- }
- int run(){
- if ( count> lowerbound)
- {
- return count--;
- } else {
- return lowerbound;
- }
- }
- };
- }
其中的upperbound,lowerbound和类counter都是有命名空间CounterNameSpace定义范围的组成部分。
在命名空间中声明的标识符是可以被直接引用的,不需要任何的命名空间的修饰符。例如,在CounterNameSapce命名空间中,run()函数中就可以直接在语句中引用lowerbound:
点击(此处)折叠或打开
- if ( count > lowerbound)
- {
- return count--;
- }
然而,既然命名空间定义了一个范围,那么我们在命名空间之外就需要使用范围解析运算符来引用命名空间中的对象。例如,在命名空间CounterNameSpace定义的范围之外给upperbound赋值为10,就必须这样写:
CounterNameSpace::upperbound = 10;
或者在CounterNameSpace定义的范围之外想要声明一个counter类的对象就必须这样写:
CounterNameSpace::counter obj;
一般来讲,在命名空间之外想要访问命名空间内部的成员需要在成员前面加上命名空间和范围解析运算符。
---------
命名空间的意义
为什么需要将函数定义在命名空间中呢?这其实是为了避免变量或函数重命名的问题。试想,一个项目组内多个工程师进行开发,有可能会出现全局变量或函数重名的现象,而如果每个人都定义了自己的命名空间,就可以解决这个问题,即使重名,只要分属不同的命名空间就不会引起问题。
这样大家应该明白了,命名空间就是将多个变量和函数等包含在内,使其不会与命名空间外的任何变量和函数等发生重命名的冲突。
命名空间实例
下面鸡啄米给出一个使用命名空间的实例。实例中有两个命名空间JiZhuoMi和Software,他们中都有一个名为szUrl的字符串,我们试着访问并输出这两个字符串。
C++代码
#include <iostream>
using namespace std;
// 命名空间JiZhuoMi
namespace JiZhuoMi
{
char *szUrl = "www.jizhuomi.com";
}
// 命名空间Software
namespace Software
{
char *szUrl = "www.jizhuomi.com/software/";
}
int _tmain(int argc, _TCHAR* argv[])
{
cout << JiZhuoMi::szUrl << endl; // 输出命名空间JiZhuoMi中的字符串
cout << Software::szUrl << endl; // 输出命名空间Software中的字符串
return 0;
}
此实例运行结果如下图:
我们看到,使用“命名空间::标识符名称”的方式就可以访问命名空间中的变量或函数了,而且即使是重复命名也可以正确访问。
using namespace *;的意义
在上面的实例中,我们访问命名空间JiZhuoMi和Software中的字符串变量时,都需要在前面加上“命名空间::”,但cout定义在命名空间std中,前面却不需要加“std::”,这是因为上面这样一条语句“using namespace std;”。
using namespace *;(这里的*表示可以是任何命名空间)的作用是释放命名空间*中的变量或函数等,使之在被访问时可以不必加“命名空间::”,访问方法与一般的变量或函数无异,就像上面的cout一样。
using namespace *;会给我们书写程序带来方便,但也要慎用,如果释放了多个命名空间中的东西后,它们又可能会引起命名冲突。鸡啄米给大家演示下同时释放JiZhuoMi和Software命名空间的情况。
C++代码
#include <iostream>
using namespace std;
// 命名空间JiZhuoMi
namespace JiZhuoMi
{
char *szUrl = "www.jizhuomi.com";
}
// 命名空间Software
namespace Software
{
char *szUrl = "www.jizhuomi.com/software/";
}
// 释放命名空间JiZhuoMi和Software
using namespace JiZhuoMi;
using namespace Software;
int _tmain(int argc, _TCHAR* argv[])
{
cout << szUrl << endl; // 这里会提示编译错误
return 0;
}
上例中,编译器会提示编译错误,因为它不知道该访问哪个命名空间中的字符串变量szUrl。这时要想正确访问,还需在szUrl前面加上命名空间修饰。
而如果main函数中又定义了一个局部变量szUrl呢?
C++代码
#include <iostream>
using namespace std;
// 命名空间JiZhuoMi
namespace JiZhuoMi
{
char *szUrl = "www.jizhuomi.com";
}
// 命名空间Software
namespace Software
{
char *szUrl = "www.jizhuomi.com/software/";
}
// 释放命名空间JiZhuoMi和Software
using namespace JiZhuoMi;
using namespace Software;
int _tmain(int argc, _TCHAR* argv[])
{
char *szUrl = "url";
cout << szUrl << endl;
return 0;
}
运行后我们发现,szUrl访问正确,可见,这种情况下,编译器优先访问局部变量。
关于命名空间的内容就讲到这里了,希望大家能够使用命名空间很好的为软件开发服务
本文来源于鸡啄米 http://www.jizhuomi.com/ , 原文地址:http://www.jizhuomi.com/software/289.html