多态性是 OOP 独有的吗?

Is polymorphism exclusive to OOP?

我是学生,不知道我的问题有没有问错。我知道在 OOP 中多态性通常是通过方法覆盖、函数重载等实现的。但它是 OOP 语言独有的概念吗?如果没有,您能否提供有关如何使用非 OOP 语言实现它的示例,包括 C 但不是它独有的? (到目前为止,我有一些 Java、C++、C、Java脚本和 PHP 经验)

谢谢。

But is it a concept exclusive to OOP languages?

有点。它是 OO 语言的定义属性。在 运行 时 select 行为的能力取决于函数调用中涉及的对象或对象是 OOP 的全部内容。

但当然还有许多其他类型的多态性。例如,C++ 通过模板支持编译时多态性。但是很多人会说这不是OOP。

多态性并不是 OOP 或类似 OOP 的系统所独有的,但正如您所指出的,它们的构想是为软件中被认为是通用思想的东西提供标准模式。它可以在没有首先 class 支持的语言中模拟(并且在某些语言中有句法帮助,例如 lua)。

在旧的过程语言中,人们使用与 C++ 相同的技巧,只是或多或少是明确的;通常是一些动态分配的数据的 void * 以及一些用于对其进行操作的函数指针。标准库 qsort 函数在一定程度上体现了这一点。

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

typedef struct Sortable {
    char *(*toString)(struct Sortable *p);
} Sortable;

typedef struct AThing {
    Sortable p;
    int value;
} AThing;

typedef struct BThing {
    Sortable p;
    const char *str;
} BThing;

int sortableCompare(const void *a, const void *b) {
    int res;
    Sortable *aa = *((Sortable **)a);
    Sortable *bb = *((Sortable **)b);
    char *astr = aa->toString(aa);
    char *bstr = bb->toString(bb);

    res = strcmp(astr, bstr);

    free(astr);
    free(bstr);

    return res;
}

char *AThing_toString(Sortable *p) {
    AThing *self = (AThing*)p;
    char *res = malloc(15);
    snprintf(res, 15, "%d", self->value);
    return res;
}

char *BThing_toString(Sortable *p) {
    BThing *self = (BThing*)p;
    return strdup(self->str);
}

AThing *createIntSortable(int i) {
    AThing *self = malloc(sizeof(*self));
    self->p.toString = AThing_toString;
    self->value = i;
    return self;
}

BThing *createStringSortable(const char *str) {
    BThing *self = malloc(sizeof(*self));
    self->p.toString = BThing_toString;
    self->str = str;
    return self;
}

int main() {
    Sortable *array[3];

    array[0] = &createIntSortable(1)->p;
    array[1] = &createStringSortable("hi")->p;
    array[2] = &createIntSortable(3)->p;

    qsort
        ( array // auto decay and coerce to void*
        , sizeof(array) / sizeof(array[0]) // nelem
        , sizeof(array[0]) // elem size
        , &sortableCompare // compare function
        );
    for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i) {
        char *p = array[i]->toString(array[i]);
        printf("%d %s\n", i, p);
        free(p);
    }

    for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i) {
        // To be more fancy, make a destructor in p                                                                                                                       
        free(array[i]);
    }
}

go 和 rust 不是严格面向对象的,而是使用接口和 duck 类型转换为所有类型提供许多与对象相同的属性。您可以用方法装饰任何东西,并选择 self 参数是按引用还是按值。

Haskell 具有类型 classes,这有点类似于多态的 go 和 rust 风格,因为提供类型的人提供了该类型的接口实现(例如,可以充当列表的对象可能会实现 Monoid)。任何采用实现 monoid 的对象的函数都可以自动将对象强制转换为 Monoid 类型 class 实现。

在没有类型 classes 的函数式语言中(甚至大部分时间在 haskell 中),人们通过编写通用的高阶函数然后传入集合来实现多态对他们关心的对象的操作。通过这种方式,你可以拥有容器、过滤器、转换器等,它们不知道它们在做什么,而是根据它们自己objective 来承担用户提供的一组操作。 elm-astar 是一个很好的完整示例,因为它使用自己没有任何多态性工具的语言实现 A*。与 C 相比,它获得了一些简洁,因为虽然多态性不是内置的,但通用类型是。

根据定义:

"In programming languages and type theory, polymorphism (from Greek πολύς, polys, "many, much" and μορφή, morphē, "form, shape") is the provision of a single interface to entities of different types.A polymorphic type is one whose operations can also be applied to values of some other type, or types".

添加到 Neil 的回答中。多态性不仅是基于继承的,尽管 generalisation 非常适合它。在 C++ 中,您可以更努力地使用 STL 的 std::variant 来应用 多态性

进一步阅读和引用:

-Polymorphism

-Another polymorphism