【问题标题】:Is polymorphism exclusive to OOP?多态性是 OOP 独有的吗?
【发布时间】:2017-03-24 23:19:40
【问题描述】:

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

谢谢。

【问题讨论】:

  • 当然,选择你最喜欢的静态类型函数语言,类型系统可能会支持多态性,例如哈斯克尔。
  • 请记住,最初的 C++ 编译器只是将 C++ 代码转换为纯 C 代码。所以它绝对可以用非 OOP 语言完成(尽管可能需要一些工作)。
  • @Some 不,这不是 cfront(最初的 C++ 编译器)所做的——它是一个真正的编译器,它发出 C 而不是汇编语言,就像许多现代编译器一样。 C With Classes 是一个预处理器,但它处理的语言不是 C++。

标签: oop language-agnostic polymorphism


【解决方案1】:

多态性并不是 OOP 或类似 OOP 的系统所独有的,但正如您所指出的,它们被认为是为软件中被认为是普遍想法的东西提供标准模式。它可以用没有一流支持的语言来模拟(并且在某些语言中具有语法帮助,例如 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 并不是严格面向对象的,而是使用接口和鸭子类型转换来赋予所有类型很多与对象相同的属性。您可以使用方法来装饰任何东西,并选择 self 参数是通过引用还是通过值。

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

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

【讨论】:

  • 回想起来,榆树的例子更像是一个泛型的例子而不是多态性的例子。我想到了用户对联合类型进行操作的想法,然后由更通用的代码调用。重要的部分是用户指定的操作可以处理任何联合替代方案。我已经在媒体上写过几次关于这个主题的文章:medium.com/@prozacchiwawa/… .. 通用性是它有用的先决条件。
【解决方案2】:

从定义:

“在编程语言和类型论中,多态性(来自希腊语 πολύς, polys, "many, much" 和 μορφή, morphē, "form, shape")是为不同类型的实体提供单一接口。 type 是一种其操作也可以应用于某种其他类型或类型的值”。

补充尼尔的答案。多态性不仅是基于继承的,即使 泛化 非常适合它。在 C++ 中,您可以更加努力地使用 STL 的 std::variant 来应用 多态性

进一步阅读和引用:

-Polymorphism

-Another polymorphism

【讨论】:

    【解决方案3】:

    但它是 OOP 语言独有的概念吗?

    有点。它是面向对象语言的定义属性。在运行时根据函数调用中涉及的一个或多个对象来选择行为的能力就是 OOP 的全部意义所在。

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

    【讨论】:

      猜你喜欢
      • 2015-10-29
      • 2019-04-16
      • 2011-09-15
      • 1970-01-01
      • 2016-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多