C语言实现面向对象

2023-04-12  本文已影响0人  ShowMeCoding

一步步分析: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 = &dd;
    //传递父类指针,将会调用子类中实现的虚函数
    Animal_Say(pa);
    return 0;
}
上一篇下一篇

猜你喜欢

热点阅读