Nếu như là một fan trung thành của C++ STL (Standard Template Library), bạn sẽ bắt gặp functor rất nhiều.
Ví dụ trong đoạn code sau:
#include <iostream> #include <vector> #include <algorithm> void increment(int& i) { ++i; std::cout << i << ' '; } int main() { std::vector<int> v = {1, 2, 3, 4, 5, 6}; void (*fun_ptr) (int&) = &increment; std::for_each(v.begin(), v.end(), increment); std::cout << std::endl; std::for_each(v.begin(), v.end(), fun_ptr); std::cout << std::endl; return 0; } |
Nếu bạn chưa dùng for_each bao giờ, bạn có thể tham khảo tài liệu về nó ở link
Hàm for_each và cũng như rất nhiều hàm trong thư viện STL (std::sort, std::count_if, std::remove_if,…) đều là những hàm nhận functor – tất nhiên functor là một danh từ chung, ở trường hợp cụ thể của mỗi hàm thì tên gọi nó lại khác nhau, ví dụ với sort thì có thể gọi là Comparator, count_if, remove_if thì lại là Predicate).
Functor – đơn giản là một thứ gì đó thực thi công việc giúp bạn.
Ở đoạn code phía trên, functor có thể là một hàm tự do, hoặc có thể là một function pointer (biến trỏ hàm).
Thực tế rằng những hàm này đã wrap các function/function pointer mà bạn truyền vào, thành một Function Object và gọi function object đó khi cần thiết.
Vậy nên chính xác hơn, functor là một function object.
Function object được sử dụng rất nhiều (hầu hết) trong thư viện STL C++, và nên viết functor để sử dụng các thuật toán, các chức năng của STL một cách hiệu quả hơn theo ý muốn.
Cũng là đoạn code ở như trên, nhưng mình sẽ dùng một function object.
#include <iostream> #include <vector> #include <algorithm> class Incrementor { public: void operator()(int& i) { ++i; std::cout << i << ' '; } }; int main() { std::vector<int> v = {1, 2, 3, 4, 5, 6}; Incrementor in; std::for_each(v.begin(), v.end(), in); std::cout << std::endl; return 0; } |
Mình đã tạo ra một object, và truyền nó vào for_each như một functor.
Function object là một object được định nghĩa toán tử (), và bạn có thể sử dụng nó như một hàm.
Code:
Incrementor in; in(1); |
hoặc
std::for_each(v.begin(), v.end(), Incrementor()); |
Trạng thái: Functor không phải một hàm, nó là một object, nên bạn có thể tùy biến theo ý mình, ví dụ viết ra một functor có khả năng config để thực thi một công việc phức tạp. Khác với một hàm thông thường rằng nó luôn cho ra kết quả với input tương ứng, luôn thực thi từ đầu đến cuối. Với functor bạn sẽ có thể tạo ra các thực thi linh hoạt hơn.
OOP tốt hơn: thiết kế các solution theo hướng sử dụng functor sẽ giúp code của bạn được tổ chức tốt hơn, logic hơn.
Tốc độ: Trình dịch sẽ cố gắng inline functor của bạn, còn với function pointer thì không.
Manh
March 11, 2016
C++