一步步分析:C语言如何面向对象编程 - 知乎 (zhihu.com)
C 语言实现面向对象编程_面向对象程序设计c语言_onlyshi的博客-CSDN博客
Animal.h
#ifndef _ANIMAL_H_
#define _ANIMAL_H_
//父类虚表的前置声明
struct AnimalVTable;
// 定义父类结构
typedef struct {
struct AnimalVTable* vptr; //虚表指针
int age;
int weight;
} Animal;
// 构造函数声明
//显示定义this指针,当调用时主动把对象的地址传递给它
void Animal_Ctor(Animal* this, int age, int weight);
//父类中的虚表
struct AnimalVTable {
void (*say)(Animal* this); //虚函数指针
};
//父类中实现的虚函数
void Animal_Say(Animal* this);
// 获取父类属性声明
int Animal_GetAge(Animal* this);
int Animal_GetWeight(Animal* this);
#endif
Animal.c
#include "assert.h"
#include "Animal.h"
//父类中虚函数的具体实现
static void _Animal_Say(Animal* this) {
//因为父类中Animal是一个抽象的东西,不该被实例化
//父类中的虚函数不应该被调用,也就是说子类必须实现这个虚函数
//类似于C++中的纯虚函数
assert(0);
}
// 父类构造函数实现
void Animal_Ctor(Animal* this, int age, int weight)
{
//首先定义一个虚表
static struct AnimalVTable animal_vtbl = { _Animal_Say };
//让虚指针指向上面这个虚表
this->vptr = &animal_vtbl;
this->age = age;
this->weight = weight;
}
//测试多态
void Animal_Say(Animal* this) {
//如果this实际指向一个子类Dog对象,那么this->vptr这个虚表指针指向子类自己的虚表
//因此,this->vptr->say将会调用子类虚表中的函数
this->vptr->say(this);
}
int Animal_GetAge(Animal* this)
{
return this->age;
}
int Animal_GetWeight(Animal* this)
{
return this->weight;
}
Dog.h
#ifndef _DOG_H_
#define _DOG_H_
#include "Animal.h"
//定义子类结构
typedef struct {
Animal parent; //第一个位置放置父类结构
int legs; //定义子类属性
} Dog;
//子类构造函数声明
void Dog_Ctor(Dog* this, int age, int weight, int legs);
//子类属性声明
int Dog_GetAge(Dog* this);
int Dog_GetWeight(Dog* this);
int Dog_GetLegs(Dog* this);
#endif
Dog.c
#include "Dog.h"
//子类中虚函数的具体表现
static void _Dog_Say(Dog* this) {
printf("dog say hello!\n");
}
//子类构造函数
void Dog_Ctor(Dog* this, int age, int weight, int legs) {
//首先调用父类构造函数,初始化从父类继承的数据
Animal_Ctor(&this->parent, age, weight);
//定义子类自己的虚函数表
static struct AnimalVTable dog_vtbl = { _Dog_Say };
//把从父类中继承得到的虚表指针指向子类自己的虚表
this->parent.vptr = &dog_vtbl;
//然后初始化子类自己的数据
this->legs = legs;
}
//子类构造函数声明
int Dog_GetAge(Dog* this) {
//age属性是继承而来,转发给父类中的获取属性函数
return Animal_GetAge(&this->parent);
}
int Dog_GetWeight(Dog* this) {
return Animal_GetWeight(&this->parent);
}
int Dog_GetLegs(Dog* this) {
//直接返回子类的属性
return this->legs;
}
main.c
#include <stdio.h>
#include "Animal.h"
#include "Dog.h"
int main() {
//封装:描述数据的组织形式,把一个对象的所有属性组织在一起,c语言使用结构体
//在栈上创建一个对象
Animal a;
//构造对象
Animal_Ctor(&a, 1, 3);
printf("age = %d, weight = %d \n",
Animal_GetAge(&a),
Animal_GetWeight(&a));
//继承:子类通过继承父类,自动拥有父类的属性和方法,c语言主要注意内存模型
Dog d;
Dog_Ctor(&d, 1, 3, 4);
printf("age = %d, weight = %d, legs = %d \n",
Dog_GetAge(&d),
Dog_GetWeight(&d),
Dog_GetLegs(&d));
//多态:描述一种动态行为,在C++中,只有通过基类引用或者指针,
//去调用虚函数的时候才发生多态,C++内部通过一个虚表实现多态
//如果一门语言只支持类,打不支持多态,只能说它是基于对象的,而不是面向对象的
Dog dd;
Dog_Ctor(&dd, 2, 2, 4);
//把子类对象赋值给父类指针
Animal* pa = ⅆ
//传递父类指针,将会调用子类中实现的虚函数
Animal_Say(pa);
return 0;
}