Menu
CoddyTech

Mô phỏng phương thức

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 39 trên 61.

Bạn đã thấy cách đặt con trỏ hàm bên trong một struct. Sức mạnh thực sự xuất hiện khi bạn gán các hàm khác nhau cho những instance khác nhau của cùng một kiểu struct. Đây là cách mô phỏng các phương thức có hành vi khác nhau.

Hãy xem một struct biểu diễn một hành động với logic có thể tùy chỉnh:

typedef void (*ActionFunc)(void);

typedef struct {
    const char* name;
    ActionFunc execute;
} Action;

Khi tạo các đối tượng, bạn kết nối từng hàm với một đối tượng:

void say_hello(void) {
    printf("Hello!\n");
}

void say_goodbye(void) {
    printf("Goodbye!\n");
}

int main() {
    Action greet = { "Greet", say_hello };
    Action farewell = { "Farewell", say_goodbye };
    
    greet.execute();    // Đầu ra: Hello!
    farewell.execute(); // Đầu ra: Goodbye!
    return 0;
}

Cả greet và farewell đều cùng kiểu (Action), nhưng gọi execute trên mỗi giá trị lại cho kết quả hoàn toàn khác nhau. Struct không chỉ chứa dữ liệu. Nó còn chứa hành vi thay đổi theo từng instance.

Mẫu này tương tự cách các đối tượng hoạt động trong những ngôn ngữ khác: mỗi đối tượng có thể có cách triển khai phương thức riêng, dù chúng dùng chung một giao diện.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống Speaker để minh họa cách các instance khác nhau của cùng một kiểu struct có thể thể hiện những hành vi hoàn toàn khác nhau, tùy thuộc vào hàm được gán cho chúng.

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

  • speaker.h: Định nghĩa một kiểu con trỏ hàm có tên SpeakFunc, không nhận tham số và không trả về giá trị nào. Sau đó, định nghĩa một struct Speaker chứa name (kiểu const char*) và một con trỏ hàm speak kiểu SpeakFunc.
  • main.c: Thêm header của bạn và triển khai ba hàm phát ra âm thanh khác nhau:
    • bark: in ra Woof!
    • meow: in ra Meow!
    • chirp: in ra Chirp!
    Sau đó, tạo hai instance Speaker, mỗi instance được gán một hàm khác nhau dựa trên đầu vào, rồi gọi phương thức speak của chúng để xem tính đa hình hoạt động.

Chương trình của bạn sẽ nhận hai đầu vào: kiểu loa thứ nhất (1 là bark, 2 là meow, 3 là chirp) và kiểu loa thứ hai (cũng là 1, 2 hoặc 3).

Tạo hai instance Speaker. Bạn có thể đặt tên tùy ý cho chúng (chẳng hạn như "Dog", "Cat", "Bird", hoặc đơn giản là "Speaker1", "Speaker2"). Gán cho mỗi instance hàm phù hợp dựa trên mã đầu vào, rồi lần lượt gọi speak trên từng instance.

Ví dụ đầu ra khi kiểu thứ nhất là 1 và kiểu thứ hai là 2:

Woof!
Meow!

Ví dụ đầu ra khi kiểu thứ nhất là 3 và kiểu thứ hai là 3:

Chirp!
Chirp!

Điểm mấu chốt ở đây là cả hai loa đều có cùng kiểu Speaker, nhưng tạo ra đầu ra khác nhau vì mỗi loa có một hàm khác nhau được gán cho thành viên speak. Hãy nhớ dùng các include guard trong tệp header.

Tự làm thử

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

// TODO: Viết hàm (function) bark để in ra "Woof!"

// TODO: Viết hàm meow để in ra "Meow!"

// TODO: Viết hàm chirp để in ra "Chirp!"

int main() {
    int type1, type2;
    scanf("%d", &type1);
    scanf("%d", &type2);
    
    // TODO: Tạo hai instance của Speaker
    
    // TODO: Gán hàm speak cho speaker thứ nhất dựa trên type1
    // (1 = bark, 2 = meow, 3 = chirp)
    
    // TODO: Gán hàm speak cho speaker thứ hai dựa trên type2
    // (1 = bark, 2 = meow, 3 = chirp)
    
    // TODO: Gọi speak trên từng speaker theo thứ tự
    
    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