目录
函数符概念
两大类:函数对象,函数指针。
四种形式:函数对象,成员函数指针,全局函数指针,Lambda表达式。
函数对象
函数对象概念
1.函数对象是一个类对象,实现类似函数调用的形式,所以也称之为仿函数。只不过这个类对象的类中重写小括号运算符重载函数。
2.可以直接使用类中的属性在函数中进行直接使用,无需进行传参。有时,在函数对象中会保存一个类中的属性变量来记录函数对象调用的状态时,此时的函数对象也被人称之为闭包。
3.函数对象的成员函数的小括号运算符重载函数,只要是符合内联的特性,编译将自动升级为内联函数,就没有函数调用的那个几个阶段了,所以函数对象调用小括号就类似于宏函数直接展开,所以函数对象的执行效率比普通函数要高很多倍。
4.使用场景:函数对象一般很少单独使用,主用的应用场景在于一个算法的策略中使用。
5.谓词:
(1).当函数对象的类中的小括号运算符,返回值为bool 时,此函数对象也被称为谓词(predicate) 。
(2).如果函数对象的类中小括号运算符的参数列表中有一个参数时,也称之为一元函数对象。
(3).如果函数对象的类中小括号运算符的参数列表中有两个参数时,也称之为二元函数对象。
(4).如果函数对象的类中小括号运算符的参数列表中有多个参数时,也称之为多元函数对象。
函数对象演示
类中小括号重写:
#include <iostream>
using namespace std;
template <class T>
class hello
{
private:
T data;
public:
hello(T data)
{
this->data = data;
}
//重写小括号运算符
void operator()()
{
cout << this->data << endl;
}
//函数重载
int operator()(int a, int b)
{
return a > b ? a : b;
}
};
主函数调用:
int main()
{
//初始化
hello<string> h1("hello");
//小括号运算符重载形式调用:
h1.operator()(); //hello
cout << "-------------" << endl;
h1(); //hello
cout << "--------------" << endl;
//运算符重载
cout << h1.operator()(10,29) << endl; //29
cout << h1(10,20) << endl; //20
return 0;
}
运行结果:
函数对象、函数指针调用演示
定义普通函数(函数指针)形式:
#include <iostream>
using namespace std;
//小于函数模板
template <class T>
T my_less(T t1, T t2)
{
return t1 < t2 ? t1 : t2;
}
//大于函数模板
template <class T>
T my_greater(T t1, T t2)
{
return t1 > t2 ? t1 : t2;
}
//以上是普通函数,调用时使用函数指针。
定义函数对象形式:
/// 使用函数对象的方式
template <class T>
class My_Less
{
public:
T operator ()(T t1, T t2)
{
return t1 < t2 ? t1 : t2;
}
};
template <class T>
class My_Greater
{
public:
T operator ()(T t1, T t2)
{
return t1 > t2 ? t1 : t2;
}
};
在全局中,定义函数模板,传入函数对象或函数指针:
template <class T, class Compair>
T compair(T t1, T t2, Compair f)
{
return f(t1, t2);
// f = my_less<int> f是一个函数指针
// f = My_Less<int>() f是一个对象
}
主函数验证:
int main()
{
int a = 10;
int b = 20;
cout << compair(a,b,my_less<int>) << endl; //10
cout << compair(a,b,my_greater<int>) << endl; //20
cout << typeid (my_less<int>).name() << endl; //FiiiE
cout << "-------以上的方式是函数指针回调实现的功能" << endl;
//通过函数对象
cout << compair(a,b, My_Less<int>()) << endl; //10
cout << typeid (My_Less<int>()).name() << endl; //F7My_lessIiEvE
cout << "-------以上的方式是函数对象回调实现的功能" << endl;
return 0;
}
运行结果:
匿名函数Lambda
概念
1.Lambda表达式就是普通函数对象的升级版。
2.Lambda无法捕捉任何static变量、全局变量,不过可以在Lambda表达式内部直接访问。
3.Lambda表达式的优势:代码更简短,调用效率与普通函数对象一样。
4.当使用[=]拷贝捕获时,lambda的底层小括号运算是由const修饰的,所以可以使用mutable进行修改。
用法
C++11自动推到关键字auto由编译器自动推导一个表达式的类型.
auto是不可以作为函数形参类型的。
auto f = []()->返回值{};
[] 就是来捕获外部变量的,如果是空的,则不捕获任何变量
[=] 就是通过拷贝复制的方式捕获外部变量
[&] 就是通过引用的方式捕获外部变量
[=,&foo] 按值捕获外部作用域中所有变量,并按引用捕获 foo 变量。
[bar] 按值捕获 bar 变量,同时不捕获其他变量。
[this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lamda 中使用当前类的成员函数和成员变量。
() 就是普通函数对象的小括号重载运算符的形参列表
-> 返回值: 这个返回值需要就写,不需要就不写
{ } 这个大括号就是小括号运算符重载函数的函数体
匿名函数代码演示:
#include <iostream>
using namespace std;
//Lambda表达式也可定义在全局
int x = 50;
int y = 60;
auto f4 = []()
{
int temp = x;
x = y;
y = temp;
};
int main()
{
auto f1 = [] (int a, int b)->int {
return a + b;
};
cout << typeid (f1).name() << endl; //Z4mainEUliiE_ (无需关心)
cout << f1(10, 20) << endl;
cout << "----------------------" << endl;
int x = 20;
int y = 30;
//C++11中所提供的一个易变关键字mutable,与const是一对立的关键字。
//因为当使用[=]号时,lambda的底层小括号运算是由const修饰的,所以可以使用mutable进行修改。
auto f2 = [=]() mutable //拷贝捕获并不会改变原有值
{
int temp = x;
x = y;
y = temp;
};
f2();
cout << "f2后" << endl;
cout << "x = " << x << endl;
cout << "y = " << y << endl;
cout << "----------------------" << endl;
auto f3 = [&]() //使用引用捕获后,会改变变量的值
{
int temp = x;
x = y;
y = temp;
};
f3();
cout << "f3后" << endl;
cout << "x = " << x << endl;
cout << "y = " << y << endl;
cout << "----------------------" << endl;
f4(); //f4的[]是空的,不捕获任何变量
cout << "f4后" << endl;
cout << "x = " << x << endl;
cout << "y = " << y << endl;
return 0;
}
运行结果:
函数包装器
包装器时基于类模板的偏特化完成的
标准库的包装器演示
三种方式的函数:
#include <iostream>
#include <functional>
using namespace std;
//全局函数
int add(int a, int b, int c)
{
return a + b + c;
}
//类的成员函数
class A
{
public:
int A_Add (int a, int b, int c)
{
return a + b + c;
}
};
//函数对象
class Add
{
public:
int operator () (int a, int b, int c)
{
return a + b + c;
}
};
主函数验证:
int main()
{
//1.使用标准库中的包装器来包装一个全局函数
function <int (int, int, int)> f1 = add;
cout << f1(10, 20, 30) << endl;
cout << "-----------1" << endl;
//2.使用标准库中的包装器来包装一个成员函数
A a;
function <int (A* const, int, int, int)> f2 = &A::A_Add; //A* const是this指针
cout << f2(&a, 10, 20, 30) << endl;
cout << "-----------2" << endl;
//3.使用标准库中的包装器来包装一个函数对象
function <int (int, int, int)> f3 = Add(); //Add()为函数对象之临时对象
cout << f3(10, 20, 30) << endl;
cout << "-----------3" << endl;
//4.使用标准库中的包装器来包装一个匿名函数对象
function <int (int, int, int)> f4 = [](int a, int b, int c){
return a + b + c;
};
cout << f4(10, 20, 30) << endl;
cout << "-----------4" << endl;
return 0;
}
运行结果:
自定义函数包装器演示
定义包装器代码:
#include <iostream>
using namespace std;
//全局函数
int add(int a, int b, int c)
{
return a + b + c;
}
//包装器基础模板
template <class T>
class myfunction
{
public:
myfunction()
{
cout << "myfunction包装器的基础类模板" << endl;
}
};
//包装器特化
template <class Ret, class ... Args>
class myfunction <Ret (Args ...)>
{
public:
using pfunc = Ret (*) (Args ...); //以下两种方式效果时相同的,using是C++11中新的用法
//typedef Ret (*pfunc) (Args ...);
private:
pfunc f;
public:
myfunction(pfunc f)
{
this->f = f;
}
Ret operator() (Args ... args)
{
return f(args...);
}
};
主函数验证:
int main()
{
int (*p)(int, int, int ) = add;
cout << p(10, 20, 30) << endl; //60
cout << typeid (p).name() << endl; //PFiiiiE
cout << "---------------------------以上是函数指针调用" << endl;
myfunction <int (int, int, int)> f = add;
cout << f(10, 20, 30) << endl; //60
cout << typeid (f).name() << endl; //10myfunctionIFiiiiEE
cout << "---------------------------以上是函数包装器调用" << endl;
return 0;
}
运行结果: