Quy tắc thành viên đầu tiê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 29 trên 61.
Khi bạn nhúng một struct làm thành viên đầu tiên của một struct khác, một điều rất hữu ích sẽ xảy ra: địa chỉ bộ nhớ của struct bên ngoài trùng với địa chỉ bộ nhớ của thành viên đầu tiên. Tiêu chuẩn C đảm bảo điều này.
Hãy xem ví dụ trước:
typedef struct {
int id;
} Parent;
typedef struct {
Parent parent; // Thành viên đầu tiên
int grade;
} Child;Khi tạo một biến Child, thành viên Parent nằm ngay ở đầu vùng nhớ của Child. Điều này có nghĩa là con trỏ đến Child trỏ đến đúng cùng một địa chỉ với con trỏ đến thành viên Parent.
Child c;
Child* child_ptr = &c;
Parent* parent_ptr = (Parent*)child_ptr; // Ép kiểu an toàn!Cả hai con trỏ đều giữ cùng một địa chỉ. Nhờ đó, bạn có thể truyền một Child* cho bất kỳ hàm nào nhận Parent*:
void print_id(Parent* p) {
printf("ID: %d\n", p->id);
}
// Trong main:
Child c;
c.parent.id = 42;
print_id((Parent*)&c); // Hoạt động hoàn hảoKỹ thuật này là nền tảng của tính kế thừa trong C. Một hàm được viết cho kiểu cơ sở có thể hoạt động với mọi kiểu dẫn xuất, miễn là kiểu cơ sở được nhúng trước tiên. Phép ép kiểu này an toàn vì bố cục bộ nhớ hoàn toàn khớp nhau.
Thử thách
DễHãy khám phá quy tắc thành viên đầu tiên bằng cách xây dựng một hệ phân cấp động vật đơn giản. Bạn sẽ tạo một cấu trúc Animal cơ sở và một cấu trúc Dog dẫn xuất, sau đó minh họa cách ép kiểu an toàn con trỏ đến Dog thành con trỏ đến Animal.
Điểm mấu chốt bạn sẽ áp dụng: khi Animal là thành viên đầu tiên của Dog, cả hai cấu trúc đều có cùng địa chỉ bộ nhớ bắt đầu. Điều này có nghĩa là bạn có thể truyền Dog* cho bất kỳ hàm nào nhận Animal* bằng cách ép kiểu con trỏ.
Bạn sẽ sắp xếp code trong ba tệp:
animal.h: Định nghĩa cả hai cấu trúc với các include guard. Cấu trúcAnimalcần có một trường duy nhất:legs(một số nguyên biểu thị số chân). Cấu trúcDogcần nhúngAnimallàm thành viên đầu tiên và thêm trườngname(một mảng ký tự gồm 50 ký tự). Đồng thời khai báo hàmprint_animalnhận tham sốAnimal*.animal.c: Triển khai hàmprint_animal. Hàm này làm việc với kiểu cơ sở. Hàm chỉ biết vềAnimalvà in ra số chân của con vật.main.c: Tạo một biếnDogvà điền các trường của nó (cả số chân của con vật được nhúng lẫn tên của chó). Sau đó, minh họa quy tắc thành viên đầu tiên bằng cách ép kiểuDog*thànhAnimal*rồi truyền con trỏ đó choprint_animal. Ngoài ra, hãy in riêng tên của chó để thấy đầy đủ kết quả.
Bạn sẽ nhận hai đầu vào: tên của chó (một chuỗi) và số chân (một số nguyên).
Đầu ra của bạn sẽ có dạng như sau:
Dog: Buddy
Legs: 4Trong đó, Buddy là tên của chó và 4 là số chân. Trước tiên, hãy in tên của chó từ main.c, sau đó gọi print_animal với con trỏ đã ép kiểu để hiển thị số chân.
Điều này minh họa cách một hàm được viết cho kiểu cơ sở (Animal) có thể làm việc liền mạch với kiểu dẫn xuất (Dog) thông qua việc ép kiểu con trỏ: nền tảng của tính kế thừa trong C.
Tự làm thử
#include <stdio.h>
#include <string.h>
#include "animal.h"
int main() {
// Đọc đầu vào
char name[50];
int legs;
scanf("%s", name);
scanf("%d", &legs);
// TODO: Tạo một biến Dog
// TODO: Gán tên cho chó bằng strcpy
// TODO: Gán số chân (truy cập qua Animal được nhúng)
// TODO: In tên chó theo định dạng: "Dog: <name>"
// TODO: Ép kiểu Dog* thành Animal* và gọi print_animal
// Điều này minh họa quy tắc thành viên đầu tiên!
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