close up photo of programming of codes

codecungnhau.com

Một trang web về kỹ thuật lập trình

Thiết kế Callbacks trong C++: Con trỏ hàm

Trong bài viết này, chúng ta sẽ thảo luận về callback là gì và những loại callback nào chúng ta có thể có trong C ++ và cách thiết kế Callback dưới dạng con trỏ hàm.

Callback là gì?

Callback (gọi lại) là một hàm mà chúng ta chuyển đến các API khác làm đối số trong khi gọi chúng. Giờ đây, các API này ​​sẽ sử dụng callback gọi lại hàm được cung cấp của chúng ta vào một thời điểm nào đó.

Có 3 kiểu callback trong c++

  • Con trỏ hàm
  • Đối tượng hàm
  • Hàm lambda

Hành vi hoặc kết quả của API phụ thuộc vào hàm callback mà ta cung cấp, tức là nếu ta giữ nguyên đầu vào cho API và chỉ cần thay đổi callback thì đầu ra của API sẽ thay đổi. Hãy tìm hiểu điều này bằng cách,

Sử dụng con trỏ hàm như là một callback

Từ framework, ta có một API có thể tạo một thông điệp hoàn chỉnh từ các dữ liệu thô được cung cấp. API này sẽ thực hiện những bước sau:

  1. Thêm header và footer vào đoạn dư liệu thô để tạo ra thông điệp.
  2. Mã hóa toàn bộ thông điệp.
  3. Trả lại thông điệp.

Bây giờ 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. API này sẽ gọi lại hàm của ứng dụng bằng cách gọi thông qua con trỏ hàm đã truyền này.

Cơ chế gọi lại (Callback)

API của Framework chấp nhận callback với con trỏ hàm là một đối số như sau,

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 message
    rawData = encrypterFunPtr(rawData);
    return rawData;
}

Giờ thì, khi một ứng dụng gọi API này của framework để xây dựng thông báo, nó sẽ truyền một con trỏ đến hàm cục bộ của nó như một đối số.

Giả sử, ta có một hàm là một callback như bên dưới. Hàm mã hóa này sẽ tăng tất cả các ký tự trong thông điệp lên 1.

std::string encryptDataByLetterInc(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;
}

Bây giờ, thử gọi API trên để tạo một thông điệp có hàm mã hóa như ta vừa mới tạo ra,

std::string msg = buildCompleteMessage("SampleString", &encryptDataByLetterInc);
std::cout<<msg<<std::endl;

Kết quả: [IFBEFS]TbnqmfTusjoh[GppUFS]

Tiếp theo, hãy tạo ra một hàm mã hóa khác. Lúc này, tất cả cá ký tự trong chuỗi sẽ bị giảm đi một.

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]--;
    }
    return data;
}

Và, kết quả khi gọi API

std::string msg = buildCompleteMessage("SampleString", &encryptDataByLetterDec);
std::cout<<msg<<std::endl;

[GD@CDQ]R`lokdRsqhmf[EnnSDQ]

Ta thấy kết quả của lần gọi này khác với trước đó. Mặc dù giữ nguyên API và dữ liệu đã chuyển nhưng ta đã thay đổi hàm callback được truyền, dẫn đến hành vi hoặc kết quả của API đã thay đổi.

Vậy là chúng ta đã biết được như thế nào gọi là callback và cách sử dụng con trỏ hàm để truyền một callback. Trong phần tiếp theo, ta sẽ tìm hiều đối tương hàm gọi lại cũng như tại sao lại cần đối tượng này.


Đã đăng vào

trong

bởi

Bình luận

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *