Định nghĩa struct mờ
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 18 trên 61.
Bây giờ bạn đã hiểu khái niệm con trỏ không trong suốt (opaque pointer), hãy cùng xem cách hoàn thiện mẫu này. Tệp header khai báo rằng một kiểu dữ liệu tồn tại, nhưng tệp mã nguồn mới là nơi bạn định nghĩa nội dung thực sự bên trong.
Đây là phần thiết lập hoàn chỉnh. Đầu tiên là tệp tiêu đề chỉ có khai báo trước:
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
typedef struct Counter Counter; // Kiểu dữ liệu chưa hoàn chỉnh
Counter *create_counter(int start);
void free_counter(Counter *c);
#endif
Sau đó, tệp mã nguồn chứa định nghĩa struct thực tế:
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value; // Ẩn với bên ngoài!
int step;
};
Counter *create_counter(int start) {
Counter *c = malloc(sizeof(Counter));
c->value = start;
c->step = 1;
return c;
}
void free_counter(Counter *c) {
free(c);
}
Điểm mấu chốt: struct Counter { ... } chỉ xuất hiện trong tệp .c. Bất kỳ tệp nào có counter.h đều biết Counter tồn tại nhưng không thể thấy value hoặc step. Nếu viết c->value trong main.c, trình biên dịch sẽ báo lỗi: các thành viên này thực sự không thể nhìn thấy.
Sự tách biệt này là nền tảng của tính đóng gói trong C. Bước tiếp theo là cung cấp quyền truy cập có kiểm soát thông qua các hàm getter và setter.
Thử thách
DễHãy tạo một module Timer minh họa mẫu con trỏ mờ đục. Bạn sẽ luyện cách giấu định nghĩa cấu trúc bên trong tệp nguồn, khiến các thành viên bên trong hoàn toàn vô hình với mọi code sử dụng module của bạn.
Bạn sẽ tạo ba tệp:
timer.h: Đây là giao diện công khai. Khai báo kiểuTimermờ đục chỉ bằng một khai báo trước, không viết phần thân cấu trúc ở đây! Đồng thời khai báo hai hàm:create_timer(nhận số nguyên chỉ số giây và trả về con trỏ Timer) vàfree_timer(nhận con trỏ Timer và giải phóng tài nguyên). Dùng include guard với ký hiệuTIMER_H.timer.c: Đây là nơi chứa phần bí mật. Định nghĩastruct Timerthực sự với hai thành viên được ẩn:int secondsvàint running(dùng 1 khi đang chạy, 0 khi đã dừng). Triển khai hàm khởi tạo để cấp phát cấu trúc, khởi tạosecondsbằng giá trị được cung cấp và đặtrunningthành 1. Triển khai hàm hủy để giải phóng bộ nhớ.main.c: Dùng module Timer để tạo bộ hẹn giờ và xác nhận tạo thành công. Vì các thành viên của cấu trúc bị ẩn, bạn không thể truy cập trực tiếp. Đó chính là mục đích! Chỉ cần in thông báo xác nhận đã tạo, sau đó giải phóng bộ hẹn giờ và in thông báo xác nhận giải phóng.
Bạn sẽ nhận một đầu vào: số giây (một số nguyên) dùng để khởi tạo bộ hẹn giờ.
Trong tệp chính, hãy tạo bộ hẹn giờ với giá trị số giây được cung cấp. In thông báo tạo thành công, sau đó giải phóng bộ hẹn giờ và in thông báo xác nhận.
In đầu ra theo định dạng sau:
Timer created
Timer freedĐiểm mấu chốt là main.c có thể làm việc với con trỏ Timer nhưng không có cách nào truy cập trực tiếp vào seconds hoặc running. Nếu thử viết t->seconds trong main.c, trình biên dịch sẽ báo lỗi vì phần thân cấu trúc chỉ được định nghĩa trong timer.c. Đây là tính đóng gói thực sự: các chi tiết triển khai hoàn toàn bị ẩn với người dùng module.
Tự làm thử
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: Tạo bộ hẹn giờ với giá trị giây đã cho
// TODO: In ra "Timer created"
// TODO: Giải phóng bộ hẹn giờ
// TODO: In ra "Timer freed"
return 0;
}
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
1Kiến thức cơ bản về lập trình mô-đun
Tệp tiêu đềInclude guardTệp mã nguồnHàm staticÔn tập: Máy tính mô-đun4Tính đóng gói
Khái niệm con trỏ mờĐịnh nghĩa struct mờHàm truy xuất và hàm gánKiểm tra tính hợp lệ trong hàm gánÔn tập: Hộp bí mật2Đối tượng và phương thức
Struct dưới dạng đối tượngCon trỏ 'Self'Tính đúng đắn của constCon trỏ và giá trịPhương thức hỗ trợÔn tập: trình quản lý Point5Dự án: Tài khoản ngân hàng đơn giản
Thiết lập dự ánTriển khai tài khoản3Vòng đời đối tượng
Mẫu hàm khởi tạoMẫu hàm hủyKhởi tạo trên ngăn xếpSao chép sâuÔn tập: lớp bao bọc chuỗi6Kế thừa bằng cách kết hợp
Nhúng structQuy tắc thành viên đầu tiênTruy cập thành viên lớp chaUpcastingÔn tập: hệ phân cấp hình dạngTự luyện tập: Trình biên dịch C online