Cocos2dx <基础> 回调函数及相关的语法

<函数指针>

指针: 是一个变量,存储的是内存地址。一个程序运行时所有和运行相关的物件都需要加载到内存中的。函数是存储在内存代码区域中的,函数同样有地址,可以用指针存放函数。

指向函数入口的地址称为函数指针。

int GetSum(int x, int y)
{
	return x+y;
}

int main()
{
//函数指针存放函数地址
int(*p) (int x, int  y);
p = GetSum;
cout << p(2,3) << endl;
 return 0;
}

<回调函数>

使用者自己定义的函数并且实现函数内容,然后将这个函数作为参数传入别人(系统)的函数运行时会调用的函数。

(别人的函数会在运行期间调用你实现的函数),

void Display()
{
	cout << "回调函数" << endl;
}

void Fun(void (*p)())
{
	p();
	cout << "实现回调函数的函数" << endl;
}

int Dop(int x)
{
	return x;
}

void fup(int (*p)(int x))
{
	cout << p(2) << endl;
}

int main()
{
	//无参数
	Fun(Display);
	//带参数
	fup(Dop);
}

<bind>

bind是一种用于函数绑定的模板,对某个函数进行绑定的时候,可以指定部分参数或者全部参数,也可以不指定参数,还可以调整各个参数之间的关系。

对于未指定的参数可以用占位符_1,_2表示。_1表示绑定后的函数的第一个参数,_2表示绑定后的函数的第二个参数。

void Diplay()
{
	cout << "bind函数绑定" << endl;
}

void Dun(int x,int y)
{
	cout << x << endl;
	cout << y << endl;
}

void Du(int& x, int& y)
{
	x++;
	y++;
}

int main()
{
	//无参数
	auto func = bind(Diplay);
	func();
	//有参数,绑定的函数不预先指定的第一个参数
	auto fnp = bind(Dun,placeholders::_1,2);
	fnp(1);
	//有参数,绑定的函数不预先指定的第一个和第二个参数
	auto fgp = bind(Dun,placeholders::_1,placeholders::_2);
	fgp(3,4);
	//不预先指定的参数是按照引用传递,预先指定的参数是按照值传递的
	int m = 5, n = 8;
	auto frh = bind(Du,m,placeholders::_1);
	frh(n);
	cout << "m=" << m << endl;
	cout << "n=" << n << endl;
}

<function>----->头文件: #include<functional>

类模板function是一种函数封装,function的实例可以对任何调用的目标进行存储,复制,调用操作。目标: 函数,lambda表达式等。

void Dun(int x)
{
	cout <<"不预先指定的参数placeholders::_1=" <<x << endl;
}

int main()
{
	//有参数,绑定的函数不预先指定的第一个参数
	bind(Dun, placeholders::_1, 2);
	function<void(int)> func = bind(Dun, placeholders::_1);
	func(1);
}

<**Lambda表达式>

a. Lambda表达式用于定义和创建匿名的函数对象,以简化编程工作。

    Lambda表达式语法: [捕捉列表]  (参数列表)  mutable/ exception   -> 返回值类型 {语句} 

b. Lambda表达式分析:

   (1)捕捉列表: 总是出现在Lambda表达式开始处,实际上[]是Lambda表达式引出符,编译器根据引出符判断接下来的代码是否是Lambda表达式。

       捕捉列表能够捕捉那些定义到Lambda为止时Lambda所在作用范围内可见的变量(包括Lambda所在类的this)。

   (2)参数列表,:与普通的参数列表一样。按照值传递和按照引用传递, 无参数时可以将这部分省略。

   (3)mutable或exception声明:这部分可以省略。按值传递捕捉列表参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改

       拷贝,而不是值本身)。exception声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用throw(int)。

   (4)->返回类型: 表示函数返回的类型。在不需要返回值的情况下,可以将->返回类型,直接省略;返回类型明确的情况下,也可以省略这部分,让编译器

       对返回类型进行推导。

   (5)函数体, 内容和普通函数一样。可以使用参数列表的参数,也可以使用捕捉列表中的参数。

c. 捕捉列表的捕捉项分析:

    [] -->表示没有捕捉项

    [= ]->表示函数体可以使用Lambda有效作用范围类的局部变量,包括所在类的this;按照值传递

    [&]->表示函数体可以使用Lambda有效作用范围类的局部变量,包括所在类的this;按照引用传递

    [this]->表示函数体可以使用Lambda所在类的成员变量

    [a]->表示a按照值传递的方式, 如果要修改a的副本,则应该加mutable

    [&a]->表示a按照引用传递的方式

    [a, &b]->表示a按照值传递,b按照引用传递

    [=,&a,&b]->表示a和b按照引用传递外,其他参数按照值传递方式

    [&,a,b]->表示a,b按照值传递的方式,其余参数按照引用传递

class Test
{
	int x = 10;
public:
	void Lambda1()
	{
		int y = 5;
		auto fun2 = [=]() { cout << y << endl; };
		fun2();
	}
	void Lambda2()
	{
		int z = 6;
		auto fun2 = [&]() { cout << z << endl;};
		fun2();
	}
	void Lambda3()
	{
		auto fun2 = [this]() { cout << this->x << endl; };
		fun2();
	}
	void Lambda4()
	{
		int a = 8;
		auto fun2 = [a]() { cout << a << endl; };
		fun2();
		auto fun3 = [a]() mutable {a++; cout << a << endl; };
		cout << a << endl;
	}
	void Lambda5()
	{
		int b = 10;
		auto fun2 = [&b]() { ++b; cout << b << endl; };
		fun2();
		cout << b << endl;
	}
	void Lambda6()
	{
		int b = 10;
		int a = 8;
		auto fun2 = [&b, a]() { ++b; cout << b << endl; cout << a << endl; };
		fun2();
	}
	void Lambda7()
	{
		int b = 10;
		int a = 8;
		auto fun2 = [&b, a](int x) {cout << a + b + x << endl; };
		fun2(5);
	}
};

int main()
{
	Test* test = new Test();
	//[]
	auto fun1 = [] {cout << "没有捕捉项" << endl; };
	//[=]
	test->Lambda1();
	//[&]
	test->Lambda2();
	//[this]
	test->Lambda3();
	//[a]
	test->Lambda4();
	//[&a]
	test->Lambda5();
	//[a,&b]
	test->Lambda6();
	//参数列表不为空
	test->Lambda7();
}


<分析Cocos2dx中的菜单回调函数>

a.  查看菜单项的create()函数

    (1) static MenuItemImage* create(const std::string&normalImage, const std::string&selectedImage, const ccMenuCallback& callback);

    (2) typedef std::function<void(Ref*)> ccMenuCallback;

    (3) ccMenuCallback-------> 函数封装,封装的函数原型为void 函数名 (Ref*)

b. 查看Cocos2dx提供的函数: CC_CALLBACK_1

    查看CC_CALLBACK_1的定义,会发现:

#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)

   分析0,1,2,3代表的是什么?    代表的是绑定的函数不预先指定的参数个数。

   我们发现CC_CALLBACK_X的函数原型----->std::bind() : 函数绑定

c. 得知菜单项的create()函数中的ccMenuCallback-------> function: 函数封装

    得知CC_CALLBACK_1的函数原型----->bind: 函数绑定

    这里的形式不一样,为什么可以使用? 原因是可以在于function函数封装

    简单的写一下:

    void Func(Ref*) { }

    funtion<void (Ref*)> = bind(Func, placeholders::_1) ;


<Cocos2dx 动作回调函数>-----> 使用回调函数作为参数

a.  创建回调动作, 使用无参数的回调函数作为参数

     static CallFunc * create(const std::function<void()>& func);

b.  创建回调动作,使用Node*作为参数的回调函数作为参数

     static CallFuncN * create(const std::function<void(Node*)>& func);


------------------------------------边学边补充-------------------------------------------------

(1).  菜单回调函数 , 动作回调函数: 使用回调函数作为参数。

(2).  接收回调函数作为参数的两种类型: function, bind

(3).  Lmabda表达式可以创建回调函数










猜你喜欢

转载自blog.csdn.net/wue1206/article/details/80182708