高级软件工程——软件中的一些特殊机制

软件中的一些特殊机制

1.回调函数

2.多态

3.闭包

4.异步调用

5.匿名函数

一,回调函数

高级软件工程——软件中的一些特殊机制

关于回调函数的概念,上图可以很清晰的描述:应用程序在调用库函数时向库函数传递参数,参数里面包含一个应用程序指定的函数。这样,库函数被调用的时候,就会过头来用这个应用程序指定的函数。被传递而后被库函数调用的函数称为回调函数(callback function)。

这么看来,回调函数会大大增加编程的灵活性。因为相比传统仅传递参数的方式,这里把函数作为参数,库函数的动作可以根据回调函数的不同而做出相应的改变。

举个简单的例子,如下:

// callBack1:接受一个非零整数,返回偶数

int cb_Even(int a){

	return 2*a;

}

// callBack2:接受一个非零整数,返回奇数

int cb_Odd(int a){

	return 2*a+1;

}

// 中间函数:接受函数指针并调用对应的回调函数

int returnNum(int a, int (*p_func)(int)){

	return (*p_func)(a);

}

// 使用:传入不同的函数参数,调用不同的回调函数

cout << returnNum(5, cb_Even) << endl; 	    // 输出10

cout << returnNum(5, cb_Odd) << endl;		// 输出11

我对回调函数的理解:发起者将目标函数A作为参数传递给中间函数,中间函数随后调用目标函数A。相比仅传递参数,将函数也传递过去可以执行不同的功能。

二,多态

高级软件工程——软件中的一些特殊机制

在面向对象编程中,多态是指通过基类的指针或引用,在运行时,根据实际绑定的对象执行对应的函数的行为。编译时绑定则是指重载或模板。关于多态的实现原理可以查阅虚函数表相关内容。

c++中,实现多态的条件:

  1. 要有继承关系;

  2. 要有虚函数重写(被 virtual 声明的函数叫虚函数);

  3. 要有父类指针(父类引用)指向子类对象。

举个简答的例子,如下:

class Person{

public:

	// 父类中的虚函数

	virtual void BuyTicket(){

		cout << "adult need full fare." << endl;

	}

}

class Child : public Person{

public:

	// 子类继承并重写了父类的虚函数

	virtual void BuyTicket(){

		cout << "child free." << endl;

	}

}
void TicketCheck(Person& person){

	// 编译时,父类指针指向自己的虚函数
	person.BuyTicket();

}

// 调用时,该指针动态指向自己或任意孩子重写的虚函数

Person father; Child tommy, Child bobby;

TicketCheck(father);		// person指针指向person

TicketCheck(tommy);	  		// person指针指向child

TicketCheck(bobby);	  		// person指针指向child

三,闭包

闭包(closure)是JavaScript中的概念,指函数与函数内部能访问到的外部变量构成的总和。

高级软件工程——软件中的一些特殊机制

比如:bar()函数和其内部能够访问到的外部变量local的组合,即为一个闭包。注意这里有一个刻意为之的函数嵌套的结构。

function foo(){

	var local = 1		// 闭包的作用就是将local变量变为局部变量

	function bar(){		// 函数嵌套,local称为bar函数的全局变量

		locat++

		return local

	}

	return bar			// 返回bar函数,外部可以间接使用local变量

}

闭包常用来隐藏一个变量,将其变为局部变量,外界通过间接访问的方式来使用这个变量。

四,异步调用

首先明确一下同步调用的概念:当发起者A调用函数B时,会一直处于阻塞状态直到函数B执行完并返回结果。异步调用则是指发起者A调用函数B后继续做其他的事情,不会等待B的执行。

原理比较简单,在C++中可以通过调用函数async()来实现异步调用。

五,匿名函数

匿名函数,顾名思义,就是没有名称的函数,在C++和大多数语言中又称为lambda表达式

下图为lambda表达式的书写规范,这里讨论第二种模式。

高级软件工程——软件中的一些特殊机制

[捕获列表](参数列表) -> 返回值类型 { 函数题 }(传递的参数列表);

举个例子,看一下普通函数和匿名函数(lambda表达式)的区别:

// 普通函数:接受2个整型值返回和
int sum(int a, int b){
    return a+b; 
}

int main(){
    int outcome=0;		// 变量用于接受结果
    
    // 调用普通函数
    outcome = sum(1, 2);
    cout << outcome << endl;
    
    // 调用lambda表达式,注意,lambda表达式可以在函数内部嵌套定义,这是优势
    outcome = [](int a, int b) -> int { return a+b; }(1, 2);
    cout << outcome << endl;
    // 或者可以写成这样
    [](int a, int b){ cout << a+b << endl; }(1, 2);
    
    return 0;
}

一般而言在C++中,无法在main函数或者其他函数内部定义新的函数,这会发生函数嵌套。从上面的例子可以看出,使用lambda表达式可以随用随定义,不用跳出函数内部。另一方面,不用给函数取名,也省了一些命名的烦恼 :)。

关于lambda表达式的进阶用法这里不再赘述,请自行查阅相关资料。

高级软件工程——软件中的一些特殊机制

上一篇:解决vue封装的echarts组件多次调用出现id重复问题


下一篇:git常用命令自己梳理总结