可能重复问题:
如何在C语言中模拟面向对象的多态性?
我正在尝试通过我所知道的语言的例子来更好地理解多态性的概念;C语言中是否有多态性?
可能重复问题:
如何在C语言中模拟面向对象的多态性?
我正在尝试通过我所知道的语言的例子来更好地理解多态性的概念;C语言中是否有多态性?
这是Nekuromento的第二个示例,按照我认为适用于面向对象C的习惯方式进行了重构:
#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
#include "animal.h"
static const char *sound(void)
{
return "meow!";
}
const struct animal_vtable_ CAT[] = { { sound } };
#include "animal.h"
static const char *sound(void)
{
return "arf!";
}
const struct animal_vtable_ DOG[] = { { sound } };
#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;
}
这是运行时多态的一个示例,因为方法解析发生在运行时。
C1x添加了泛型选择,通过宏实现编译时多态成为可能。下面的示例摘自C1x 4月份草案第6.5.1.1 §5节:
#define cbrt(X) _Generic((X), \
long double: cbrtl, \
default: cbrt, \
float: cbrtf \
)(X)
C99中已经通过头文件tgmath.h
提供了用于数学函数的类型通用宏,但是没有办法让用户定义自己的宏而不使用编译器扩展。
DOG
和 CAT
放在 animal.h
文件中是惯例吗?我可以想象它们也可以放在各自的头文件中。 - Brady Dean在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;
}
通过使用函数指针,您可以创建虚拟表并将其用于创建“对象”,这些对象在运行时会被统一处理,但会有不同的行为。
#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;
}
struct animal
的methods
成员定义为指针,以便同一“类”的不同实例可以共享它们的虚函数表。 - Christophtgmath.h
的头文件中添加了适用于算术类型的多态数学函数;C1x则增加了_Generic
,使得用户定义的多态宏成为可能。 - Christoph