You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C语言中模拟OOP构造Animal实例:能否省略手动赋值construct函数指针的步骤?

在C中模拟OOP:隐藏构造函数指针赋值,实现单语句实例构造

你遇到的问题很典型——在C里模拟类的时候,不想让用户手动去设置构造函数的函数指针,希望像高级语言那样用一行代码完成实例化和初始化。我们可以通过工厂函数或者封装初始化逻辑来解决这个问题,下面给你两种可行的方案:

方案1:使用工厂函数(动态分配实例)

这种方式最接近高级语言里的new关键字,直接返回一个已经完全初始化好的Animal实例,用户不需要手动处理任何函数指针赋值。

修改后的animal.h

#ifndef ANIMAL_H
#define ANIMAL_H
#include <stdio.h>
#include <string.h>

typedef struct Animal Animal;

// 工厂函数:创建并初始化Animal实例
Animal* Animal_create(char *name, unsigned int weight);
// 可选:添加销毁函数,释放动态分配的内存
void Animal_destroy(Animal *self);

struct Animal {
    // 属性
    char name[50];
    unsigned int weight;
    // 方法
    void (*move)(Animal *, char*);
    unsigned int (*get_name_length)(Animal *);
};
#endif

修改后的animal.c

#include "animal.h"
#include <stdlib.h>

static void Animal_move(Animal *self, char *moveType) {
    printf("%s is moving (%s)...\n", self->name, moveType);
}

static unsigned int Animal_get_name_length(Animal *self) {
    printf("Getting %s name length...\n", self->name);
    return strlen(self->name);
}

// 内部初始化逻辑,封装所有函数指针赋值
static void Animal_init(Animal *self, char *name, unsigned int weight) {
    strcpy(self->name, name);
    self->weight = weight;
    self->move = Animal_move;
    self->get_name_length = Animal_get_name_length;
}

Animal* Animal_create(char *name, unsigned int weight) {
    // 动态分配内存
    Animal *new_animal = malloc(sizeof(Animal));
    if (new_animal == NULL) {
        perror("Failed to allocate memory for Animal");
        return NULL;
    }
    // 调用内部初始化函数
    Animal_init(new_animal, name, weight);
    return new_animal;
}

void Animal_destroy(Animal *self) {
    if (self != NULL) {
        free(self);
    }
}

修改后的main.c

#include "animal.h"

int main(void) {
    // 单语句完成实例创建+初始化
    Animal *dog = Animal_create("Doge", 8);
    if (dog == NULL) {
        return 1;
    }

    // 调用方法
    dog->move(dog, "walking");
    printf("%s weight property is %u kilograms.\n", dog->name, dog->weight);
    printf("%s name has %u characters.\n", dog->name, dog->get_name_length(dog));

    // 记得释放内存
    Animal_destroy(dog);
    return 0;
}

方案2:封装初始化函数(栈上分配实例)

如果你不想用动态内存分配,希望在栈上创建实例,可以把初始化逻辑封装成一个函数,用户只需要声明实例,然后调用这个初始化函数即可,同样不需要手动设置函数指针。

修改后的animal.h

#ifndef ANIMAL_H
#define ANIMAL_H
#include <stdio.h>
#include <string.h>

typedef struct Animal Animal;

// 初始化函数:初始化已声明的Animal实例
void Animal_init(Animal *self, char *name, unsigned int weight);

struct Animal {
    // 属性
    char name[50];
    unsigned int weight;
    // 方法
    void (*move)(Animal *, char*);
    unsigned int (*get_name_length)(Animal *);
};
#endif

修改后的animal.c

#include "animal.h"

static void Animal_move(Animal *self, char *moveType) {
    printf("%s is moving (%s)...\n", self->name, moveType);
}

static unsigned int Animal_get_name_length(Animal *self) {
    printf("Getting %s name length...\n", self->name);
    return strlen(self->name);
}

void Animal_init(Animal *self, char *name, unsigned int weight) {
    strcpy(self->name, name);
    self->weight = weight;
    self->move = Animal_move;
    self->get_name_length = Animal_get_name_length;
}

修改后的main.c

#include "animal.h"

int main(void) {
    // 声明实例 + 单语句初始化
    Animal dog;
    Animal_init(&dog, "Doge", 8);

    // 调用方法
    dog.move(&dog, "walking");
    printf("%s weight property is %u kilograms.\n", dog.name, dog.weight);
    printf("%s name has %u characters.\n", dog.name, dog.get_name_length(&dog));

    return 0;
}

为什么这两种方案能解决你的问题?

  • 我们把函数指针赋值和属性初始化的逻辑都封装到了Animal_create或Animal_init函数里,用户完全不需要接触到内部的函数指针设置,就像使用高级语言的构造函数一样。
  • 方案1的工厂函数还帮你处理了内存分配,避免了手动管理内存的麻烦(记得用完调用Animal_destroy释放);方案2则保留了栈分配的轻量性,适合不需要长期存活的实例。

另外,注意你原来的代码里有个拼写错误:weigth应该是weight,我在修改后的代码里已经修正了这个问题。

内容的提问来源于stack exchange,提问作者Citra Dewi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 18:08:14