Menu
CoddyTech

Khái niệm interface

Thuộc phần Lập trình hướng đối tượng trong hành trình C của Coddy. Bài học 40 trên 61.

Đến giờ, các struct của chúng ta đã kết hợp dữ liệu và hành vi với nhau, chẳng hạn như một tên cùng với một con trỏ hàm. Nhưng nếu một struct chỉ chứa các con trỏ hàm thì sao? Điều này tạo ra một thứ rất mạnh mẽ: một giao diện.

Giao diện định nghĩa những thao tác nào có sẵn mà không chỉ rõ chúng hoạt động như thế nào. Đây là một hợp đồng quy định rằng “mọi đối tượng triển khai giao diện này đều phải cung cấp các hàm (function) này”.

typedef void (*LogFunc)(const char* message);

typedef struct {
    LogFunc log;
} ILogger;

Cấu trúc ILogger chỉ chứa một con trỏ hàm. Nó không có dữ liệu riêng. Cấu trúc này chỉ mô tả hành vi. Tiền tố "I" là quy ước phổ biến để chỉ đây là một giao diện.

Bất kỳ đoạn code nào nhận ILogger đều không quan tâm thông báo nhật ký sẽ được gửi đi đâu. Nó có thể in ra màn hình console, ghi vào tệp hoặc gửi dữ liệu qua mạng. Bên gọi chỉ cần biết rằng nó có thể gọi log:

void process(ILogger* logger, const char* msg) {
    logger->log(msg);  // Chúng ta không biết nó ghi nhật ký NHƯ THẾ NÀO
}

Sự tách biệt này là cốt lõi của tính đa hình. Hàm process hoạt động với mọi cách triển khai bộ ghi nhật ký. Bạn có thể thay đổi hành vi mà không cần sửa code của hàm. Trong bài học tiếp theo, bạn sẽ tạo các cách triển khai cụ thể đáp ứng hợp đồng giao diện này.

challenge icon

Thử thách

Dễ

Hãy tạo một giao diện ICalculator: một struct chỉ chứa các con trỏ hàm, xác định những phép toán mà mọi máy tính cần hỗ trợ mà không chỉ định cách thực hiện chúng.

Bạn sẽ tạo hai tệp để sắp xếp code:

  • calculator.h: Định nghĩa giao diện tại đây. Tạo một kiểu con trỏ hàm tên là BinaryOp, nhận hai tham số int và trả về một int. Sau đó, định nghĩa một struct ICalculator chỉ chứa hai con trỏ hàm: operate (có kiểu BinaryOp) và describe (một con trỏ hàm không nhận tham số và không trả về giá trị nào). Struct này chỉ là một giao diện. Nó không chứa dữ liệu, chỉ có hành vi.
  • main.c: Đưa tệp header vào và triển khai các hàm cụ thể có thể đáp ứng giao diện:
    • add: trả về tổng của hai số nguyên
    • multiply: trả về tích của hai số nguyên
    • describe_add: in ra Addition
    • describe_multiply: in ra Multiplication
    Sau đó, tạo một instance ICalculator, gán các hàm phù hợp dựa trên đầu vào và dùng nó để thực hiện phép tính.

Chương trình của bạn sẽ nhận ba đầu vào: hai số nguyên và một mã phép toán (1 để cộng, 2 để nhân).

Dựa trên mã phép toán, gán cặp hàm phù hợp cho ICalculator. Sau đó, gọi describe thông qua giao diện để in tên phép toán, rồi gọi operate để tính và in kết quả.

Đầu ra ví dụ khi đầu vào là 5, 3 và 1:

Addition
8

Đầu ra ví dụ khi đầu vào là 4, 7 và 2:

Multiplication
28

Điểm mấu chốt là struct ICalculator định nghĩa một hợp đồng: mọi code sử dụng nó đều biết rằng có thể gọi describe và operate mà không cần biết những hàm cụ thể nào được gán vào. Nhớ dùng include guard trong tệp header.

Tự làm thử

#include <stdio.h>
#include "calculator.h"

// TODO: Triển khai hàm add
// Trả về tổng của hai số nguyên


// TODO: Triển khai hàm multiply
// Trả về tích của hai số nguyên


// TODO: Triển khai hàm describe_add
// In ra "Addition"


// TODO: Triển khai hàm describe_multiply
// In ra "Multiplication"


int main() {
    int num1, num2, op_code;
    scanf("%d", &num1);
    scanf("%d", &num2);
    scanf("%d", &op_code);
    
    // TODO: Tạo một instance ICalculator
    
    
    // TODO: Dựa vào op_code (1 là add, 2 là multiply),
    // gán các hàm phù hợp cho máy tính
    
    
    // TODO: Gọi describe thông qua giao diện
    
    
    // TODO: Gọi operate qua giao diện và in ra kết quả
    
    
    return 0;
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch C online