包装器和绑定器
- 乃神器也
- 可调用对象、包装器std:function、绑定器std:bind
- 应用场景:可变函数和参数、回调函数、取代虚函数
可调用对象
在C++中,可以像函数一样调用的有:普通函数、类的静态成员函数、仿函数、lambda函数、类
的成员函数、可被转换为函数的类的对象,统称可调用对象或函数对象。
可调用对象有类型,可以用指针存储它们的地址,可以被引用(类的成员函数除外)
普通函数
普通函数类型可以声明函数、定义函数指针和函数引用,但是,不能定义函数的实体。
#include<algorithm>
#include<iostream>
using namespace std;
using Fun = void(int, const string&);//普通函数类型别名
Fun show;//声明普通函数
//void show(int, const string&);//声明普通函数
int main() {
show(1, "我是一只小小鸟");//直接调用普通函数
void(*fp1)(int, const string&) = show;//声明函数指针,指向普通函数
void(&fr1)(int, const string&) = show;//声明函数指针,引用普通函数
fp1(2, "我是一只傻傻鸟");//用函数指针调用普通函数
fr1(3, "我是一只傻傻鸟");//用函数引用调用普通函数
//下面是C++写法
Fun* fp2 = show;//声明函数指针,指向普通函数
Fun& fr2 = show;//声明函数引用,指向普通函数
fp2(4, "我是一只傻傻鸟");//用函数指针调用普通函数
fr2(5, "我是一只傻傻鸟");//用函数引用调用普通函数
}
//定义普通函数
void show(int bh, const string& message) {
cout << "亲爱的" << bh << "," << message << endl;
}
//以下代码是错误的,不能用函数类型定义函数的实体
//Func show1{
// cout << "亲爱的" << bh << "," << message << endl;
//}
类的静态成员函数
类的静态成员函数和普通函数本质上是一样的,把普通函数放在类中而已。
#include<algorithm>
#include<iostream>
using namespace std;
using Fun = void(int, const string&);//普通函数类型别名
Fun show;//声明普通函数
//void show(int, const string&);//声明普通函数
struct AA {
static void show(int bh, const string& message) {
cout << "亲爱的" << bh << "," << message << endl;
}
};
int main() {
AA::show(1, "我是一只傻傻鸟。");// 直接调用静态成员函数。
void(*fp1)(int, const string&) = AA::show; //用函数指针指向静态成员函数。
void(&fr1)(int, const string&) = AA::show;//引用静态成员函数。
fp1(2, "我是一只傻傻鸟。");//用函数指针调用静态成员函数。 -
fr1(3, "我是一只傻傻鸟。");//用函数引用调用静态成员函数。
Fun * fp2 = AA::show;//用函数指针指向静态成员函数。
Fun& fr2 = AA::show;//引用静态成员函数。
fp2(4, "我是一只傻傻鸟。");//用函数指针调用静态成员函数。
fr2(5, "我是一只傻傻鸟。");//用函数引用调用静态成员函数。
}
仿函数
仿函数的本质是类,调用的代码像函数。
仿函数的类型就是类的类型。
#include<algorithm>
#include<iostream>
using namespace std;
struct BB {//仿函数
void operator()(int bh, const string& message) {
cout << "亲爱的" << bh << "," << message << endl;
}
};
int main() {
BB bb;
bb(11, "我是一只傻傻鸟");//用对象调用仿函数
BB()(12, "我是一只傻傻鸟");//用匿名对象调用仿函数。
BB& br = bb;//引用函数
br(13, "我是一只傻傻鸟");//用对象引用调用仿函数
}
lambda函数
lambda函数的本质是仿函数,仿函数的本质是类。
#include<algorithm>
#include<iostream>
using namespace std;
int main() {
//创建lambda对象
auto lb = [](int bh, const string& message) {
cout << "亲爱的" << bh << "," << message << endl;
};
auto& lr = lb;
lb(1, "我是一只傻傻鸟");
lr(2, "我是一只傻傻鸟");
}
类的非静态成员函数
类的非静态成员函数只有指针类型,没有引用类型,不能引用。
类的非静态成员函数有地址,但是,只能通过类的对象才能调用它,所以,C++对它做了特别处理。
类的非静态成员函数只有指针类型,没有引用类型,不能引用。
#include<algorithm>
#include<iostream>
using namespace std;
struct CC {
void show(int bh, const string& message) {
cout << "亲爱的" << bh << "," << message << endl;
}
};
int main() {
CC cc;
cc.show(14, "我是一只傻傻鸟。");
//void (*fp11)(int, const string&);//这是普通函数指针,多了CC::
void (CC:: * fp11)(int, const string&) = &CC::show;//定义类的成员函数的指针
(cc.*fp11)(15, "我是一只傻傻鸟。");///用类的成员函数的指针调用成员函数。
using pFun = void (CC::*)(int, const string&);//类成员函数的指针类型。
pFun fp12 = &CC::show;// 让类成员函数的指针指向类的成员函数的地址
(cc.*fp12)(16, "我是一只傻傻鸟。");//用类成员函数的指针调用类的成员函数。
}
可被转换为函数指针的类对象
类可以重载类型转换运算符operator数据类型()
,如果数据类型是函数指针或函数引用类型,那么
该类实例也将成为可调用对象。
它的本质是类,调用的代码像函数。
在实际开发中,意义不大。