Đối tượng hàm là gì?
Một đối tượng hàm hay một functor là một loại Callback có trạng thái.
Theo thuật ngữ của lập trình, đối tượng của một lớp có toán tử được nạp chồng () được gọi là đối tượng hàm hoặc Functor. Tức là, một lớp có hàm toán tử () được nạp chồng như sau,
#include <iostream>
class MyFunctor
{
public:
int operator()(int a , int b)
{
return a+b;
}
};
Giờ ta hãy thử tạo đối tượng hàm và gọi nó,
MyFunctor funObj;
std::cout<<funObj(2,3)<<std::endl;
Đối tượng hàm hay functor có thể được gọi giống như các hàm thông thường, tức là
MyFunctor funObj;
funObj(2,3);
là tương tự như đoạn code sau,
MyFunctor funObj;
funObj.operator ()(2,3);
Hãy tìm hiểu bằng một ví dụ thực tế.
Ví dụ thực tế
Trong phần trước, chúng ta đã thảo luận về cách sử dụng con trỏ hàm để thay đổi hành vi của API tạo thông báo. Có thể xem lại bài viết ở đây Phát biểu của bài toán như sau,
Từ một framework, chúng ta có một API có thể tạo thông điệp hoàn chỉnh từ dữ liệu thô được cung cấp. API này sẽ thực hiện các bước sau,
- Thêm header và footer vào đoạn dư liệu thô để tạo ra thông điệp.
- Mã hóa toàn bộ thông điệp.
- Trả lại thông điệp.
API này biết header và footer là gì nhưng lại không biết về logic mã hóa chính xác, vì điều đó không được thiết lập trong framework, có thể thay đổi từ ứng dụng này sang ứng dụng khác. Vì logic mã hóa phụ thuộc vào ứng dụng, do đó trong API này cung cấp một điều khoản để truyền logic mã hóa như một con trỏ hàm gọi lại.
std::string buildCompleteMessage(std::string rawData,
std::string (*encrypterFunPtr)(std::string)) {
// Add some header and footer to data to make it complete message
rawData = "[HEADER]" + rawData + "[FooTER]";
// Call the callBack provided i.e. function pointer to encrypt the
rawData = encrypterFunPtr(rawData);
return rawData;
}
Giả sử trong ứng dụng của chúng ta, ta muốn gọi API này ba lần với 3 loại mã hóa khác nhau, tức là
Mã hóa bằng cách tăng từng chữ cái lên 1.
Mã hóa bằng cách tăng từng chữ cái lên 2.
Mã hóa bằng cách giảm từng chữ cái đi 1.
Đối với trường hợp này, chúng ta cần tạo ba loại hàm khác nhau và sử dụng chúng như con trỏ hàm trong khi gọi API này. Ba hàm khác nhau ở đây là cần thiết vì các hàm toàn cục bình thường không có bất kỳ trạng thái nào được liên kết với chúng,
//This encrypt function increment all letters in string by 1.
std::string encryptDataByLetterInc1(std::string data) {
for (int i = 0; i < data.size(); i++)
if ((data[i] >= 'a' && data[i] <= 'z')
|| (data[i] >= 'A' && data[i] <= 'Z'))
data[i]++;
return data;
}
//This encrypt function increment all letters in string by 2.
std::string encryptDataByLetterInc2(std::string data) {
for (int i = 0; i < data.size(); i++)
if ((data[i] >= 'a' && data[i] <= 'z')
|| (data[i] >= 'A' && data[i] <= 'Z'))
data[i] = data[i] + 2;
return data;
}
//This encrypt function increment all letters in string by 1.
std::string encryptDataByLetterDec(std::string data) {
for (int i = 0; i < data.size(); i++)
if ((data[i] >= 'a' && data[i] <= 'z')
|| (data[i] >= 'A' && data[i] <= 'Z'))
data[i] = data[i] - 1;
return data;
}
int main() {
std::string msg = buildCompleteMessage("SampleString",
&encryptDataByLetterInc1);
std::cout << msg << std::endl;
msg = buildCompleteMessage("SampleString", &encryptDataByLetterInc2);
std::cout << msg << std::endl;
msg = buildCompleteMessage("SampleString", &encryptDataByLetterDec);
std::cout << msg << std::endl;
return 0;
}
Vậy, có cách nào để ràng buộc trạng thái với con trỏ hàm không? Câu trả lời là có – Bằng cách tạo ra đối tượng hàm hoặc functor.
Hãy tạo một đối tượng hàm hay functor để mã hóa
Một đối tượng hàm hoặc functor, là một đối tượng có toán tử () được định nghĩa là hàm thành viên, tức là,
class Encryptor {
bool m_isIncremental;
int m_count;
public:
Encryptor() {
m_isIncremental = 0;
m_count = 1;
}
Encryptor(bool isInc, int count) {
m_isIncremental = isInc;
m_count = count;
}
std::string operator()(std::string data) {
for (int i = 0; i < data.size(); i++)
if ((data[i] >= 'a' && data[i] <= 'z')
|| (data[i] >= 'A' && data[i] <= 'Z'))
if (m_isIncremental)
data[i] = data[i] + m_count;
else
data[i] = data[i] - m_count;
return data;
}
};
Các đối tượng hàm này có thể được gọi giống như các hàm trong API tạo thông điệp.
std::string buildCompleteMessage(std::string rawData,
Encryptor encyptorFuncObj) {
// Add some header and footer to data to make it complete message
rawData = "[HEADER]" + rawData + "[FooTER]";
// Call the callBack provided i.e. function pointer to encrypt the
rawData = encyptorFuncObj(rawData);
return rawData;
}
Điều vừa xảy ra ở đây là một đối tượng tạm thời của EncryptFunctor được tạo ra và toán tử () được gọi trên nó.
Nó cũng có thể được gọi như sau,
Encryptor(true, 1);
tương đương với cách gọi,
Encryptor tempObj;
tempObj.operator(true, 1);
Bây giờ hãy sử dụng đối tượng hàm này để giải quyết vấn đề của chúng ta. Tạo một đối tượng hàm có thể mã hóa bằng cách tăng / giảm từng chữ cái theo số lần xác định.
int main() {
std::string msg = buildCompleteMessage("SampleString", Encryptor(true, 1));
std::cout << msg << std::endl;
msg = buildCompleteMessage("SampleString", Encryptor(true, 2));
std::cout << msg << std::endl;
msg = buildCompleteMessage("SampleString", Encryptor(false, 1));
std::cout << msg << std::endl;
return 0;
}
Code thực thi hoàn chỉnh như sau,
#include <iostream>
class Encryptor {
bool m_isIncremental;
int m_count;
public:
Encryptor() {
m_isIncremental = 0;
m_count = 1;
}
Encryptor(bool isInc, int count) {
m_isIncremental = isInc;
m_count = count;
}
std::string operator()(std::string data) {
for (int i = 0; i < data.size(); i++)
if ((data[i] >= ‘a’ && data[i] <= ‘z’)
|| (data[i] >= ‘A’ && data[i] <= ‘Z’))
if (m_isIncremental)
data[i] = data[i] + m_count;
else
data[i] = data[i] – m_count;
return data;
}
};
std::string buildCompleteMessage(std::string rawData,
Encryptor encyptorFuncObj) {
// Add some header and footer to data to make it complete message
rawData = "[HEADER]" + rawData + "[FooTER]";
// Call the callBack provided i.e. function pointer to encrypt the
rawData = encyptorFuncObj(rawData);
return rawData;
}
int main() {
std::string msg = buildCompleteMessage("SampleString", Encryptor(true, 1));
std::cout << msg << std::endl;
msg = buildCompleteMessage("SampleString", Encryptor(true, 2));
std::cout << msg << std::endl;
msg = buildCompleteMessage("SampleString", Encryptor(false, 1));
std::cout << msg << std::endl;
return 0;
}
Để lại một bình luận