几个概念:
- 函数调用运算符:()
- 调用函数的方法是,首先是函数名,后面跟(),如果函数有参数,在函数调用位置的函数名后的圆括号中给出实参,在函数定义位置函数名后的圆括号中给出形参。
- 如果在类中重载了(),可以像调用函数一样调用该类的对象。使用方法是,定义一个该类对象,在对象()中增加实参列表。注意函数对象和类构造函数的区分。
- 如果两个函数(可调用对象)的形参和返回值相同,可以说两个函数的调用形式相同。一种调用形式对应一种函数类型。
- 如果希望把可调用对象的指针保存起来方便后期调用,一个想法是利用函数指针。函数的指针自然可以用函数指针保存,但系统不会把重载了函数调用运算符的类及其对象看成函数指针。
- C++11引入了function类模板,可以用来包装可调用对象。这时,函数、函数对象都可以识别。但如果函数有重载的情况,编译就会报错。这时可以通过定义一个函数指针解决。
// biggerthanzero.h
#pragma once
#include <iostream>
// 定义一个不输出负数的类
class biggerthanzero {
public:
// 默认构造函数
biggerthanzero() = default;
// 带参数的构造函数,打印一条消息
explicit biggerthanzero(int i) {
std::cout << "The construct func\n";
}
// 函数调用运算符重载,接收一个整数参数
int operator()(int value) const {
return (value < 0) ? 0 : value;
}
};
// 声明一个函数,接受一个整数参数并返回处理后的结果
int echovalue(int value);
// 重载,声明一个无参数的函数
void echovalue();
// biggerthanzero.cpp
#include <iostream>
int echovalue(int value) {
std::cout << value << std::endl;
return value;
}
void echovalue() {
std::cout << "重载" << std::endl;
}
// main.cpp
#include "biggerthanzero.h" // 包含自定义类的头文件
#include <iostream>
#include <map>
#include <functional>
int main() {
// 创建一个biggerthanzero类的对象,初始化值为1,注意和函数调用运算符的区别
biggerthanzero obj(1);
// 调用biggerthanzero对象的重载运算符(),并输出结果
std::cout << obj(23) << std::endl;
// 调用echovalue函数并输出结果
std::cout << echovalue(-1) << std::endl;
// 使用函数指针调用echovalue函数
int(*p)(int) = echovalue;
int c = (*p)(23);
// 使用std::map来存储函数指针
std::map<std::string, int(*)(int)> myoper;
myoper.insert({"ev", echovalue});
// 直接将类或对象作为函数指针是不允许的,因此需要使用std::function
// 定义函数指针,并用std::function封装
std::function<int(int)> f1 = p; // 因为有重载,用函数指针初始化std::function
std::function<int(int)> f2 = obj; // 用类对象初始化std::function
std::function<int(int)> f3 = biggerthanzero(); // 使用默认构造函数初始化std::function
// 使用std::map来存储std::function
std::map<std::string, std::function<int(int)>> myoper2;
myoper2.insert({"ev", f1});
myoper2.insert({"bt", f2});
myoper2.insert({"bt2", f3});
// 通过std::function调用存储的函数
std::cout << myoper2["ev"](1) << std::endl;
std::cout << myoper2["bt"](2) << std::endl;
std::cout << myoper2["bt2"](-1) << std::endl;
return 0;
}