多态性(C)

Bel*_*lgi 13 c oop polymorphism

可能重复:
我如何在C中模拟OO风格的多态?

我试图用我所知道的语言中的例子来更好地理解多态性的概念; C中有多态吗?

Chr*_*oph 35

这是Nekuromento的第二个例子,我考虑了面向对象C的惯用方式:

animal.h

#ifndef ANIMAL_H_
#define ANIMAL_H_

struct animal
{
    // make vtable_ a pointer so they can be shared between instances
    // use _ to mark private members
    const struct animal_vtable_ *vtable_;
    const char *name;
};

struct animal_vtable_
{
    const char *(*sound)(void);
};

// wrapper function
static inline const char *animal_sound(struct animal *animal)
{
    return animal->vtable_->sound();
}

// make the vtables arrays so they can be used as pointers
extern const struct animal_vtable_ CAT[], DOG[];

#endif
Run Code Online (Sandbox Code Playgroud)

cat.c

#include "animal.h"

static const char *sound(void)
{
    return "meow!";
}

const struct animal_vtable_ CAT[] = { { sound } };
Run Code Online (Sandbox Code Playgroud)

dog.c

#include "animal.h"

static const char *sound(void)
{
    return "arf!";
}

const struct animal_vtable_ DOG[] = { { sound } };
Run Code Online (Sandbox Code Playgroud)

main.c中

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

int main(void)
{
    struct animal kitty = { CAT, "Kitty" };
    struct animal lassie = { DOG, "Lassie" };

    printf("%s says %s\n", kitty.name, animal_sound(&kitty));
    printf("%s says %s\n", lassie.name, animal_sound(&lassie));

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是运行时多态性的一个例子,就像方法解析一样.

C1x添加了通用选择,可以通过宏实现编译时多态性.以下示例取自C1x April草案,第6.5.1.1节§5:

#define cbrt(X) _Generic((X), \
    long double: cbrtl, \
    default: cbrt, \
    float: cbrtf \
)(X)
Run Code Online (Sandbox Code Playgroud)

用于数学函数的类型通用宏已经通过标头在C99中可用tgmath.h,但是用户无法在不使用编译器扩展的情况下定义自己的宏.


Nek*_*nto 13

C中运行时多态的几乎所有实现都将使用函数指针,因此这是基本构建块.

这是一个简单的例子,当程序运行时行为根据它的参数而改变时.

#include <stdio.h>

int tripple(int a) {
    return 3 * a;
}

int square(int a) {
    return a * a;
}

void transform(int array[], size_t len, int (*fun)(int)) {
    size_t i = 0;
    for(; i < len; ++i)
        array[i] = fun(array[i]);
}

int main() {
    int array[3] = {1, 2, 3};
    transform(array, 3, &tripple);
    transform(array, 3, &square);

    size_t i = 0;
    for (; i < 3; ++i)
        printf("%d ", array[i]);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用函数指针,您可以创建虚拟表并使用它来创建将被统一处理的"对象",但在运行时表现不同.

#include <stdio.h>

struct animal_vtable {
    const char* (*sound)();
};

struct animal {
    struct animal_vtable methods;
    const char* name;
};

const char* cat_sound() {
    return "meow!";
}

const char* dog_sound() {
    return "bark!";
}

void describe(struct animal *a) {
    printf("%s makes \"%s\" sound.\n", a->name, a->methods.sound());
}

struct animal cat = {{&cat_sound}, "cat"};
struct animal dog = {{&dog_sound}, "dog"};

int main() {
    describe(&cat);
    describe(&dog);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 不是那个低音吗? (5认同)
  • “Woof”是 RFC K9 中建立的 Dog 发出的惯用噪音 (2认同)