继承

核心技巧:基类作为子类第一个字段

C 标准保证:结构体首字段的地址 == 结构体本身的地址,所以 (Vehicle*)&car 转换是安全的。

基类

typedef struct {
    char brand[32];
    int  year;
} Vehicle;

void Vehicle_init(Vehicle* v, const char* brand, int year) {
    strncpy(v->brand, brand, sizeof(v->brand) - 1);
    v->brand[sizeof(v->brand) - 1] = '\0';
    v->year = year;
}

void Vehicle_print(const Vehicle* v) {
    printf("Vehicle{brand=%s, year=%d}", v->brand, v->year);
}

子类 Car(继承 Vehicle)

typedef struct {
    Vehicle base;       /* 继承 —— 首字段就是基类 */
    int     doors;      /* 扩展字段 */
} Car;

void Car_init(Car* c, const char* brand, int year, int doors) {
    Vehicle_init(&c->base, brand, year);  // 先初始化"父类部分"
    c->doors = doors;                     // 再初始化自己
}

void Car_print(const Car* c) {
    printf("Car{brand=%s, year=%d, doors=%d}",
           c->base.brand, c->base.year, c->doors);
}

子类 Bike(继承 Vehicle)

typedef struct {
    Vehicle base;
    int     has_basket;
} Bike;

void Bike_init(Bike* b, const char* brand, int year, int has_basket) {
    Vehicle_init(&b->base, brand, year);
    b->has_basket = has_basket;
}

向上转型演示

int main(void) {
    Car  car;
    Bike bike;
    Car_init(&car,  "Toyota", 2020, 4);
    Bike_init(&bike, "Giant",  2023, 1);

    /* 向上转型:子类指针 → 基类指针(安全) */
    Vehicle* v1 = (Vehicle*)&car;
    Vehicle* v2 = (Vehicle*)&bike;

    Vehicle_print(v1);   // 输出基类共有的信息
    Vehicle_print(v2);
    return 0;
}