常规C中非法多态性的方法?

时间:2018-11-10 13:11:38

标签: c data-structures polymorphism

嗨,我目前正在尝试学习C,我想知道是否有一种方法可以在包含其他不同类型结构的列表的结构中实现多态?

一个这样的例子是这样的:

  #include <stdlib.h>
#include <stdio.h>

typedef void (*update_t)(void *);

typedef struct entity entity_t;
typedef struct compA compA_t;
typedef struct compB compB_t;


struct compA{

    update_t update;
};

struct compB{

    update_t update;
};

struct entity{
    update_t update;
    int curSize;
    void **components;
};


void compA_update(void *c){
    printf("updating: componentA\n");
}

compA_t *compA_create(){
    compA_t *c = malloc(sizeof(compA_t));
    c->update = compA_update;
    return c; 
}

void compB_update(void *c){
    printf("updating: componentB\n");
}


compB_t *compB_create(){
    compB_t *c = malloc(sizeof(compB_t));
    c->update = compB_update;
    return c; 
}


void entity_update(void *en){
    entity_t *e = (entity_t *)en;
    for(int i = 0; i < e->curSize; i++){
        //would like to somehow update all the components with one line just iterating through the array but does not seem possible
    }
    return;
}



entity_t *entity_create(){
    entity_t *e = malloc(sizeof(entity_t));
    e->curSize = 0;
    e->update = entity_update;
    calloc(32, sizeof(void *));
    return e;
}

void add_component(entity_t *e, void *c){
    printf("%d\n", e->curSize);
    e->components[e->curSize] = c;
    e->curSize++;
    return;
}




int main(void){

    entity_t *e = entity_create();
    compA_t *a = compA_create();
    compB_t *b = compB_create();
    add_component(e, a);
    add_component(e, b);

    e->update(e);

    return 0;
}

到目前为止,我对这个问题的解决方法已通过元组结构的空指针数组解决,该数组包含一个枚举类型,该枚举类型标识该结构以及该结构本身,然后在潜在的更新功能中,一个相当丑陋的switch语句必须可以针对每种特定类型使用案例来实现。

有更好的方法吗?如果数组中有许多不同类型,则切换方法将很快变得相当疯狂。这意味着必须为每种类型显式添加案例,并且每种案例都做完全相同的事情,在这种情况下,称为“更新”的函数指针。

1 个答案:

答案 0 :(得分:0)

您可以尝试使用数据多态性代替函数指针。也就是说,不同的数据使用相同的代码会产生不同的行为。

例如,一个简单的多态行为:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>

typedef const char* ccstr;

typedef struct animal_attr_t
{
    bool is_body_segmented;
    float gill_completeness;
    float lung_completeness;
} animal_attr_t;

typedef struct species
{
    ccstr name, kingdom, domain;

    animal_attr_t animal_attr[0];
} species;

void initialize_species_base(species *this, ccstr name, ccstr kingdom, ccstr domain)
{
    this->name = name;
    this->kingdom = kingdom;
    this->domain = domain;
}

void initialize_animal_attr(animal_attr_t *this, bool is_body_segmented, float gill_completenss, float lung_completeness)
{
    this->is_body_segmented = is_body_segmented;
    this->gill_completeness = gill_completenss;
    this->lung_completeness = lung_completeness;
}

void print_species(species*);

int main(int argc, char *argv[])
{
    species *yeast = calloc(sizeof(species), 1);
    assert(yeast);

    initialize_species_base(yeast, "yeast", "fungus", "eukaryote");

    print_species(yeast);

    species *dog = calloc(sizeof(species) + sizeof(animal_attr_t), 1);
    assert(dog);

    initialize_species_base(dog, "dog", "animal", "eukaryote");
    initialize_animal_attr(dog->animal_attr, true, 0.0f, 1.0f);

    print_species(dog);

    free(yeast);
    free(dog);
}

void print_species(species *this)
{
    printf("name = %s, kingdom = %s, domain = %s",
           this->name, this->kingdom, this->domain);

    if (strcmp(this->kingdom, "animal") == 0) {
        animal_attr_t *ani_attr = this->animal_attr;
        printf(", has %s, %f completeness of gill, %f completeness of lung",
               ani_attr->is_body_segmented ? "segmented body" : "unsegmented body",
               ani_attr->gill_completeness, ani_attr->lung_completeness);
    }

    printf(".\n");
}

yeastdog是2种完全不同的类型,但是对于species,它以统一的方式表示,print_species具有多态行为。