Menu
CoddyTech

Tổng quan về dự án

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

challenge icon

Thử thách

Dễ

Hãy đặt nền móng cho dự án Shape Drawer bằng cách tạo cấu trúc Shape cơ sở: một giao diện xác định những gì mọi hình dạng có thể làm thông qua các con trỏ hàm (function pointer).

Bạn sẽ tạo hai tệp để thiết lập hệ thống đa hình này:

  • shape.h: Định nghĩa giao diện cốt lõi tại đây. Trước tiên, tạo khai báo trước cho cấu trúc Shape. Sau đó, định nghĩa hai kiểu con trỏ hàm:
    • DrawFunc: nhận tham số const Shape* và không trả về giá trị nào
    • AreaFunc: nhận tham số const Shape* và trả về một giá trị double
    Cuối cùng, định nghĩa chính cấu trúc Shape, trong đó có hai con trỏ hàm: draw (kiểu DrawFunc) và area (kiểu AreaFunc). Cấu trúc này chỉ đóng vai trò là giao diện. Nó không chứa dữ liệu riêng của hình dạng, chỉ chứa hành vi.
  • main.c: Chứng minh giao diện hoạt động bằng cách tạo một hình dạng kiểm thử đơn giản. Triển khai hai hàm:
    • test_draw: in ra Drawing test shape
    • test_area: trả về 42.0
    Tạo một đối tượng Shape, kết nối nó với các hàm kiểm thử này, rồi gọi cả hai thông qua giao diện. In kết quả diện tích với một chữ số thập phân.

Kết quả đầu ra của bạn cần chứng minh rằng các con trỏ hàm hoạt động chính xác:

Drawing test shape
Area: 42.0

Tại sao cần khai báo trước? Bạn có thể thắc mắc tại sao typedef struct Shape Shape; lại xuất hiện trước khi cấu trúc được định nghĩa đầy đủ. Điều này cần thiết vì DrawFunc và AreaFunc tham chiếu đến const Shape* trong kiểu tham số, nhưng tại thời điểm đó trong tệp, trình biên dịch chưa thấy định nghĩa đầy đủ của cấu trúc. Khai báo trước cho trình biên dịch biết: "có một cấu trúc tên là Shape", như vậy là đủ để dùng con trỏ trỏ đến cấu trúc đó. Định nghĩa đầy đủ sẽ xuất hiện sau. Đây là cách làm phổ biến trong C khi một cấu trúc cần tham chiếu đến chính nó, trực tiếp hoặc thông qua con trỏ hàm.

Điểm mấu chốt ở đây là Shape không biết gì về hình tròn hay hình chữ nhật. Nó chỉ biết rằng mọi hình dạng đều phải có khả năng tự draw và tính area của mình. Trong các bài học tiếp theo, bạn sẽ tạo những hình dạng cụ thể nhúng cấu trúc cơ sở này và cung cấp phần triển khai riêng. Nhớ dùng include guard trong tệp tiêu đề.

Tự làm thử

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

// TODO: Triển khai hàm test_draw
// - Nhận một tham số const Shape*
// - In ra "Drawing test shape"
void test_draw(const Shape* shape) {
    // TODO: In ra thông báo theo yêu cầu
}

// TODO: Triển khai hàm test_area
// - Nhận một tham số const Shape*
// - Trả về 42.0
double test_area(const Shape* shape) {
    // TODO: Trả về giá trị diện tích dùng để kiểm thử
}

int main() {
    // TODO: Tạo một instance của Shape
    
    // TODO: Liên kết shape với các hàm test_draw và test_area
    
    // TODO: Gọi draw thông qua giao diện
    
    // TODO: Gọi area thông qua giao diện và in ra kết quả với một chữ số thập phân
    // Định dạng: "Area: %.1f\n"
    
    return 0;
}

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