C++可调用对象学习笔记

可调用对象定义:

具有函数行为或功能的一组语句视为可调用对象;一组执行任务的语句都可以视为一个函数,一个可调用对象。在程序设计的过程中,我们习惯于把那些具有复用性的一组语句抽象为函数,把变化的部分抽象为函数的参数。C++中具有函数这种行为的方式有很多。

1.普通函数 
2.类成员函数
3.类静态函数
4.函数指针
5.重载了函数调用运算符的类(该类的对象又称为:函数对象或仿函数)
6.Lamada表达式
7.标准库function类型
8.标准库bind函数

1、    普通函数定义与调用很简单,不再赘述。
2、    3、类成员函数与类静态成员函数的区别
(1)类静态成员函数被类的所有的对象共有,不属于某一个对象。通过类名::就可以直接调用。
(2)类成员函数的参数列表中隐含着类this指针,类静态成员函数跟普通的成员函数比,没有隐藏的this指针作为参数。这一点可用于封装线程类。
(3)静态成员函数只可以访问静态成员变量。

4、    函数指针
(1)函数指针:指向函数的指针变量。 因此“函数指针”本身首先应是指针变量,只不过该指针变量指向了函数。
(2)函数指针有两个用途:调用函数和做函数的参数。
(3)函数指针的声明方法为:
返回值类型 ( * 指针变量名) ([形参列表]);

 demo:

#include <iostream>

using namespace std;
// 声明一个compute函数指针;该函数指针指向:有两个int型参数并且返回值为int型的函数,这也是该指针的类型
typedef int(*compute)(int, int);

int max(int x, int y) { return x >= y ? x : y; }
int min(int x, int y) { return x <= y ? x : y; }
int add(int x, int y) { return x + y; }
int multiply(int x, int y) { return x * y; }

// 一个包含函数指针作为回调的函数
int compute_x_y(int x, int y, int(*compute)(int, int))
{
	//调用回调函数
	return compute(x, y);
}

int main(void)
{
	int x = 2;
	int y = 5;
	std::cout << "max: " << compute_x_y(x, y, max) << std::endl; // max: 5
	std::cout << "min: " << compute_x_y(x, y, min) << std::endl; // min: 2
	std::cout << "add: " << compute_x_y(x, y, add) << std::endl; // add: 7
	std::cout << "multiply: " << compute_x_y(x, y, multiply) << std::endl; // multiply: 10

	// 无捕获的lambda可以转换为同类型的函数指针
	auto sum = [](int x, int y)->int { return x + y; };
	std::cout << "sum: " << compute_x_y(x, y, sum) << std::endl; // sum: 7

	getchar();
	return 0;
}

5.重载了函数调用运算符的类(该类的对象又称为:函数对象或仿函数)
(1)函数对象:就是一个重载'()'运算符的类的对象。这样就可以直接使用‘对象名()’的方式,这跟调用函数一样,所以称谓函数对象。函数对象(function object)是一个程序设计的对象允许被当作普通函数来调用。C++函数对象实质上是运算符“()”(操作符)重载。
(2)函数对象:
【1】函数对象是指该对象具备函数的行为;
【2】函数对象,是通过()函数调用运算符声明得到的,然后便能通过函数方式来调用该对象了;
【3】()函数调用运算符可以定义不同参数的多个重载函数;
【4】()函数调用运算符只能通过类的成员函数重载,不能通过全局函数;
【5】函数对象用于在工程中取代函数指针。

(3)函数对象与普通函数区别
函数对象,可以封装自己的成员以及其它函数,所以能够更好的面向对象。
普通函数,往往只具备逻辑关系,并且没有固定的成员,因为普通函数一被调用完后,里面的内容便被摧毁了,除非使用全局变量,但是全局变量又不具备封装性。
(4)Demo

#include <iostream>

using namespace std;

class Functor
{
public:
	int operator()(int a, int b)
	{
		return a < b;
	}
};

int main()
{
	Functor f;
	int a = 5;
	int b = 7;
	int ans = f(a, b);
}

6.    Lamada表达式
6.1、定义
Lambda函数,又可以称为Lambda表达式或者匿名函数。在C++11中加入标准。定义形式如下:
                                 [captures list] (parameters list) -> return type { function body}
captures list(捕获列表),是一个lambda所在函数定义的局部变量的列表(通常为空);
parameters list,为匿名函数参数列表,当匿名函数没有参数时,可以省略。
->return type,指定匿名函数返回值类型,可以忽略,c++11的特性,可以自动类型推导。
function body,部分为函数体,包括一系列语句
除捕获列表外,参数列表、函数体与普通函数一样。返回值类型,必须 使用尾置返回来指定返回类型;尾置返回类型跟在形参列表后面以一个->符号开头,为了表示函数真正的返回类型跟在形参列表之后,我们在本应该出现返回类型的地方放置一个auto。

bool func1(int i) { return i % 3 == 0; }
//函数func1()对应的lambda表达式为:
auto func2 = [](int x) -> bool { return x % 3 == 0; };
//省略返回值类型
auto func3 = [](int x) { return x % 3 == 0; };

6.2、Lambda函数捕获列表

与普通函数最大的区别是,Lambda函数还可以通过捕获列表访问一些上下文中的数据。具体地,捕捉列表[]中变量,可以被Lambda函数使用。

下面是各种捕获选项:
[] :  不捕获任何变量
[&] :捕获外部作用域中所有变量,并作为引用在匿名函数体中使用
[=]: 捕获外部作用域中所有变量,并拷贝一份在匿名函数体中使用
[x, &y]:x按值捕获, y按引用捕获
[&, x]:  x按值捕获. 其它变量按引用捕获
[=, &y]:y按引用捕获. 其它变量按值捕获
[this] :捕获当前类中的this指针,如果已经使用了&或者=就默认添加此选项

6.3、Lambda函数的优点/作用
(1)定义位于使用的地方的附近,Lambda是理想的选择,因为其定义和使用在同一个地方进行。
(2)简洁,与函数对象相比,Lambda函数不需要定义一个类,可以在其它函数内部定义。
(3)效率,函数指针方法阻止了内联,因为编译器不会内联其地址被获取的函数。而函数符和Lambda函数通常不会阻止内联。
(4)功能,Lambda可以访问作用域内的任何动态变量,把要捕获的变量放在中括号内。[&]让你能够按引用访问所有动态变量。

补充:谓词函数与可调用对象:
接受一个参数的函数,叫做一元函数,如果一元函数返回布尔值,则该函数成为一元谓词;这种函数可供STL算法进行判断。常用于find_if、remove_if以满足相应的情况来查找或者删除。接受两个参数的函数为二元函数,如果返回一个布尔值,则该函数称为二元谓词;这种函数用于诸如std::sort等STL函数中,如下使用二元谓词对存储std::string 值的容器进行不区分大小写的排序;二元谓词,在判断两个对象时经常使用到。
但是,如果在一个算法使用中,需要更多的参数,超出了对谓词的限制,则可以考虑lambda表达式。即多元谓词(多个参数)的情形,我们可以用lambda表达式来充当谓词。同理,函数、函数指针、重载了函数调用运算符的类都可以当作谓词。

7.    标准库function类型(C++ Primer14.8.3)
8.    标准库bind函数(C++ Primer10.3.4)
注:7、8编程暂未遇到,有待学习。

参考:

 https://blog.csdn.net/u010984552/article/details/53634513
 http://blog.sina.com.cn/s/blog_720484f101016q04.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值