Part 5:函数对象
函数对象(仿函数):重载了函数调用运算符的类创建的对象,将所有的函数形式进行统筹,实现容器的定制化操作。
1、function
函数类型的容器。包装具有指定函数调用签名的任意可复制构造类型的可调用对象
- 普通函数 | 成员函数
- 函数指针
- 重载了函数调用运算符的类创建的对象
// std::function 相当于是函数类型的容器 // 1、std::bind + std::function 绑定普通函数 std::function<> f = std::bind(add, 1, 2); cout << f() << endl; // 输出 3 std::function<int(int)> f1 = std::bind(add, 1, _1); cout << f1(10) << endl; // 输出 11 std::function<int(int, int)> f2 = std::bind(add, 1, _2); // 不推荐,这里只为了演示 cout << f2(10, 11) << endl; // 输出 12 ///2、std::bind + std::function 绑定普通函数 std::function<> f = std::bind(&MyTest::add, &mytest, 1, 2); cout << f() << endl; // 输出 3 std::function<int(int)> f1 = std::bind(&MyTest::add, &mytest, _1, 2); cout << f1(10) << endl; // 输出 12 std::function<int(int, int)> f2 = std::bind(&MyTest::add, mytest, _1, _1); cout << f2(10, 20) << endl; // 输出 20
2、function + bind 多态
关于 bind 的方法:见我的博客 C++ STL:适配器 Adapter 中的函数适配器部分。
多态的实现机制
- 继承 + 虚函数
- 回调函数:组件 + 接口
function + bind
通过函数对象,注册回调函数,实现多态,取代继承 + 虚函数实现多态的机制。相比于虚函数多态机制,回调函数多态机制具有灵活性:
- 不再需要虚函数。虚函数本身就很严格
- 不再需要继承。聚合
- 非常直接,想调用哪个方法,注册对应的回调函数即可
例如:计算图形的面积
测试1:继承 + 虚函数实现的多态
#include <math.h> #include <iostream> #include <string> #include <memory> using std::cout; using std::endl; using std::string; using std::unique_ptr; class Figure { public: virtual void display() const =0; virtual double area()=0; virtual ~Figure() {} }; class Circle: public Figure { public: Circle(double radius) : _radius(radius) {} void display() const { cout << "circle"; } double area() { return 3.14159 * _radius * _radius; } ~Circle() { cout << "~Circle()" << endl; } private: double _radius; }; class Rectangle: public Figure { public: Rectangle(double length, double width) : _length(length) , _width(width) {} ~Rectangle() { cout << "~Rectangle()" << endl; } void display() const { cout << "rectangle"; } double area() { return _length * _width; } private: double _length; double _width; }; class Triangle: public Figure { public: Triangle(double a, double b, double c) : _a(a), _b(b), _c(c) {} ~Triangle() { cout << "~Triangle()" << endl; } void display() const { cout << "triangle";} double area() { double p = (_a + _b + _c) / 2; return sqrt(p * (p - _a) * (p - _b) * (p - _c)); } private: double _a; double _b; double _c; }; void display(Figure * fig) { fig->display(); cout << "的面积是:" << fig->area() << endl; } int main(void) { Rectangle rectangle(10, 20); Circle circle(10); Triangle triangle(3, 4, 5); display(&rectangle); display(&circle); display(&triangle); return 0; }
测试2:function + bind 实现的多态
#include <math.h> #include <iostream> #include <string> #include <memory> #include <functional> using std::cout; using std::endl; using std::string; using std::unique_ptr; /* 通过 std::function + std::bind 取代继承 + 虚函数, 实现多态的机制 这种多态机制的灵活性体现在: 1. 不再需要虚函数,虚函数本身就是很严格 2. 不再需要继承 3. 非常直接,想调用哪个方法,注册对应的回调函数即可 */ // Figure 不是抽象类,而是一个具体类 class Figure { public: using DisplayCallback = std::function<void()>; using AreaCallback = std::function<double()>; Figure() { cout << "Figure()" << endl;}; ~Figure() {} void setCallbacks(DisplayCallback && cb1, AreaCallback && cb2) { _displayCallback = std::move(cb1); _areaCallback = std::move(cb2); } void handleDisplayCallback() { if(_displayCallback){ _displayCallback(); } } double handleAreaCallback() { if(_areaCallback) return _areaCallback(); else return 0; } DisplayCallback _displayCallback; AreaCallback _areaCallback; }; // 不再使用继承 class Circle { public: Circle(double radius) : _radius(radius) {} void display() const { cout << "circle"; } double area() { return 3.14159 * _radius * _radius; } ~Circle() { cout << "~Circle()" << endl; } private: double _radius; }; class Rectangle { public: Rectangle(double length, double width) : _length(length), _width(width) {} ~Rectangle() { cout << "~Rectangle()" << endl; } void print() const { cout << "rectangle"; } double calcArea() { return _length * _width; } private: double _length; double _width; }; class Triangle { public: Triangle(double a, double b, double c) : _a(a), _b(b), _c(c) {} ~Triangle() { cout << "~Triangle()" << endl; } void show() const { cout << "triangle";} double getArea() { double p = (_a + _b + _c) / 2; return sqrt(p * (p - _a) * (p - _b) * (p - _c)); } private: double _a; double _b; double _c; }; void display(Figure & fig) { fig.handleDisplayCallback(); cout << "的面积是:" << fig.handleAreaCallback() << endl; } int main(void) { Rectangle rectangle(10, 20); Circle circle(10); Triangle triangle(3, 4, 5); // 1、注册回调函数 // 2、执行回调函数 Figure fig; fig.setCallbacks( std::bind(&Rectangle::print, &rectangle), std::bind(&Rectangle::calcArea, &rectangle)); display(fig); cout << endl; fig.setCallbacks( std::bind(&Circle::display, &circle), std::bind(&Circle::area, &circle)); display(fig); cout << endl; fig.setCallbacks( std::bind(&Triangle::show, &triangle), std::bind(&Triangle::getArea, &triangle)); display(fig); return 0; }