文章目录
- 引入
- function的使用
- function类型的典型应用
- function类型的原理
- 实现
- 代码优化
- 可变参的函数对象
引入
还记得C语言中的函数指针数组吗?
我们通过函数指针数组实现一个,图书管理系统的界面:
#include <stdio.h>
void doShowAllBooks() {
printf("查看所有书籍信息\n");
}
void doBorrow() {
printf("借书\n");
}
void doBack() {
printf("还书\n");
}
void doQueryBooks() {
printf("查询书籍\n");
}
void doLoginOut() {
printf("注销\n");
}
int main() {
int choice = 0;
void (*actionArray[5])() = {doShowAllBooks, doBorrow, doBack, doQueryBooks, doLoginOut};
while (1) {
printf("----------------\n");
printf("1.查看所有书籍信息\n");
printf("2.借书\n");
printf("3.还书\n");
printf("4.查询书籍\n");
printf("5.注销\n");
printf("----------------\n");
printf("请选择: ");
scanf("%d", &choice);
if (choice < 1 || choice > 5) {
printf("输入数字无效,重新选择\n");
} else {
// 调用相应的函数
(*actionArray[choice - 1])();
}
}
return 0;
}
我们通过函数指针数组集中保留了我们的函数,让巧用显得十分方便,那么在C++中,我们也有类似的实现。
function的使用
我觉得function简单一点来理解就是它能够保留可调用对象,
function是一个模板,当我们创建这个模板的时候需要一些额外的信息,所谓的额外信息就是指该function类型能够表示的对象的调用形式:
function<int(int, int)>
表示我们生命里一个function类型,它可以接受两个int、返回一个int的可调用对象。
void hello1() {
cout << "hello world!" << endl;
}
void hello2(string str) { //void (*pfunc) (string)用函数指针调用
cout << str << endl;
}
int sum(int a, int b) {
return a + b;
}
class Test {
public: //成员方法的调用必须依赖一个对象void (Test::*pfunc) (string)
void hello(string str) {cout << str << endl; }
};
int main () {
//从function 的类模板定义处,用一个函数类型实例化function
function<void()> func1 = hello1; // func1(hello1)
func1(); //func1.operator() ==> hello1()
function<void(string)> func2 = hello2;
func2("hello hello2"); //dunc2.operator(string str) ==> hello2(str)
function<int(int, int)> func3 = sum;
cout << func3(1, 1) << endl;
//保留函数对象 operator()
function<int(int, int)> func4 = [](int a, int b)->int {return a + b; };
cout << func4(100, 200) << endl;
//对类的成员方法也可以进行保留 hello有两个参数 一个是this指针一个是string str
function<void(Test*, string str)> func5 = &Test::hello;
Test t;
//func5(&Test(), "call Test::hello"); 报错,至少clang g++不允许
func5(&t, "Call Test::hello");
return 0;
}
function类型的典型应用
通过定义map和function类型实现一个读书管理系统。
void doShowAllBooks() { cout << "查看所有书籍信息" << endl; }
void doBorrow() { cout << "借书" << endl; }
void doBack() { cout << "还书" << endl; }
void doQueryBooks() { cout << "查询书籍" << endl; }
void doLoginOut() { cout << "注销" << endl; }
int main()
{
int choice = 0;
// 用C语言的函数指针其实也可以实现这个例子(采用数组来映射函数指针)
// 但是他不能实现lambda表达式和函数对象
map<int, function<void()>> actionMap;
actionMap.insert({1, doShowAllBooks}); // insert(make_pair(xx, xx));
actionMap.insert({2, doBorrow});
actionMap.insert({3, doBack});
actionMap.insert({4, doQueryBooks});
actionMap.insert({5, doLoginOut});
for (;;)
{
cout << "----------------" << endl;
cout << "1.查看所有书籍信息" << endl;
cout << "2.借书" << endl;
cout << "3.还书" << endl;
cout << "4.查询书籍" << endl;
cout << "5.注销" << endl;
cout << "----------------" << endl;
cout << "请选择: ";
cin >> choice;
auto it = actionMap.find(choice);
if (it == actionMap.end()) {
cout << "输入数字无效,重新选择" << endl;
} else {
it->second();
}
function类型的原理
通过举例来说明,有如下例子,func1可以打印hello world!
void hello(string str) { cout << str << endl; }
int main () {
function<void(string str)> func1(hello); // func1 = hello;
func1("hello world");
return 0
}
实现
通过分析我们可以知道function我们可以使用模板类来实现它,在这个模板类中,我们需要使用一个函数指针来指向hello函数。然后需要重载函数调用运算符。
- 首先我们需要实现一个通用的模板类
my_function
,这个通用模板类不需要任何实现。仅仅让编译器找到匹配的模板类定义
//my_function<void(string)> func1(hello);
template<typename Fty>
class my_function { };
- 实现特例化的模板类
template<typename R, typename A1>
//my_function<void(string)> func1(hello);
class my_function<R(A1)> {
public:
using PFUNC = R (*) (A1);
my_function(PFUNC pfunc) : _func(pfunc) {}
R operator() (A1 arg) const {return _pfunc(arg); } //hello(arg)
private:
PFUNC _pfunc;
}
- 调用检验
int main() {
my_function<void(string)> func1(hello); // 定义了一个函数对象,类型为void(string)
func1("Hello, world!"); // func1.operator()("Hello, world!");
return 0;
}
代码优化
如果我们要使用function来保存int sum(int a, int b)
呢?我们岂不是又要实现一个特例化的模板类?答案肯定是不用!
void hello(string str) { cout << str << endl; }
int sum(int a, int b) { return a + b; }
int main () {
function<void(string)> func1(hello); // func1 = hello;
func1("hello world");
function<void(int a, int b)> func2(sum);
cout << func2(10, 20) << endl;
return 0
}
可变参的函数对象
template<typename R, typename... Args> //可变参的类型参数
class my_function<R(Args...)> {
public:
using PFUNC = R (*) (Args...);
my_function(PFUNC pfunc) : _pfunc(pfunc) {}
R operator()(Args... args) const {
return _pfunc(args...);
} //hello(arg)
private:
PFUNC _pfunc;
};