【问题标题】:Alternative to polymorphism in non-OOP programming?在非 OOP 编程中替代多态性?
【发布时间】:2012-08-23 21:22:33
【问题描述】:

假设我们有一个包含不同元素的绘图程序,例如圆形、矩形、三角形等。不同类型的对象都需要类似的功能,例如 draw() 来显示自己。

我想知道程序员将如何解决如今通常由多态性解决的问题,即通过一组不相同的元素并跨不同对象调用通用功能。

想到的一种方法是拥有一个结构,其中包含指向适当函数(或函数指针数组中的索引)的函数指针以及指向实际实例的 void 指针,并将转换为的指针传递给函数中的正确类型。但这正是我——一个对这个问题一无所知的人会这样做的方式。

我确实意识到这可能是一个愚蠢的问题,但由于我在“过去”的日子里没有出现过,我真的很想知道这个问题是如何解决的。在过程编程中使用了什么样的方法,它是否具有性能优势,因为我们都知道多态性即使在像 C++ 这样的快速语言中也会因为虚方法查找而产生开销。

【问题讨论】:

  • 所以你的问题是在 OO 语言之前编程是什么样的?我想围绕如何构建最终演变成 OO 的程序的概念进行工作?例如。类通常与捆绑了方法的结构相同。
  • @Cratylus - 不,我的问题并不打算那么广泛,我确实意识到幕后有哪些课程,我只是想知道这个特定问题,如果有更有效的问题,我最感兴趣避免虚拟方法的性能开销的方法。
  • 这似乎是一个优化问题。因为理论上很慢而丢弃 OO 太仓促了。在我看来,您应该只在探查器告诉您的时间和地点“优化 OO”。
  • 您在结构中描述的方式将是我的第一个猜测。你会在 Linux 内核中看到很多这样的内容。

标签: oop polymorphism procedural-programming


【解决方案1】:

一个非常简单的例子。

如果您对此感兴趣,您可以在 Linux 内核中找到更多内容。

#include <stdio.h>                                                              

struct shape {                                                                  
    void (*say_hello)(void);                                                    
};                                                                              

void circle_say_hello(void)                                                     
{                                                                               
    printf("Hi I am circle!\n");                                                
}                                                                               

void square_say_hello(void)                                                     
{                                                                               
    printf("Meh I am square.\n");                                               
}                                                                               

#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))                                  

int main(int argc, char *argv[])                                                
{                                                                               
    struct shape circle = { .say_hello = circle_say_hello, };                   
    struct shape square = { .say_hello = square_say_hello, };                   
    struct shape* shapes[] = {&circle, &square};                                
    int i;                                                                      

    for (i = 0; i < ARRAY_SIZE(shapes); i++) {                                  
        if (shapes[i] && shapes[i]->say_hello)                                  
            shapes[i]->say_hello();                                             
    }                                                                           

    return 0;                                                                   
}  

【讨论】:

    【解决方案2】:

    在诸如 C 之类的过程语言中,这将通过为每个自定义数据类型(可能表示为结构)定义 draw() 函数的单独实现来解决。任何通用功能都将被分解为一个单独的函数,该函数对每个结构的共享元素进行操作(例如对象中心的 x 和 y 坐标,它们将出现在每个结构中)。从代码和功能的角度来看,这与使用多态性的 OOP 布局没有太大区别,在这种布局中,您仍然必须在基类中实现共享的 draw() 方法并在特定的子类中覆盖它。在过程语言的情况下,我们只是不会将这些函数定义拆分为单独的“对象”。

    有一些奇特的方法可以从过程语言中获得类似对象的行为,例如联合类型或带有额外布尔值的单个整体类型,以确定是否正在使用特定元素。这将允许您编写一个 draw() 函数,该函数可以根据启用的元素执行逻辑切换。在实践中,我唯一看到的大部分是在基于 CORBA 的系统中,其中用 C 编写的程序必须模仿通过 IDL 传播的 OOP 语言的某些行为(即,将 Java 对象转换为构造可以解码为 C 风格的结构)。

    至于 C++ 和 Java 等语言中虚方法查找的开销,这在面向对象语言中是无法完全避免的。正确使用final 关键字(它允许编译器/JVM 优化方法查找表)可以很好地缓解这种情况。

    【讨论】:

      【解决方案3】:

      这不是对您的示例的直接回答,而是您评论的地址,这显示了错误的观点恕我直言

      我只是想知道那个特定的问题,最感兴趣的是 如果有更有效的方法可以避免性能开销 虚拟方法

      这里有一些东西要理解。 一切都有权衡。设计模式和 OO 具有我们喜爱的所有已知优点,但也有缺点,例如太多的类,内存开销,由于许多方法调用导致的性能开销等。

      另一方面,旧的“程序”方式也有一些优点,即客观性;代码“简单”(无需考虑如何设计系统,只需将所有内容放在 main 中)并且在许多方面具有更少的开销(更少的内存开销,因为需要更少的类和更紧凑的对象 - 不需要虚拟表等等-和更少的方法调用,因此可能有更好的性能,没有动态绑定的性能开销——不管现在的开销是什么......-)。

      但这不是特定问题实例的权衡,而是经验表明什么是构建软件的正确方法。 重用代码是模块化并有助于单独测试(质量保证)、可读 strong>、可维护、灵活地扩展是众所周知的属性,应该是软件开发的主要驱动力。

      因此,在某些情况下,C/C++ 中非常优秀的程序员可以按照您所说的“旧方式”进行操作,但是它为这个特定程序带来的性能优势值得事实之后没有人能够维持或维持它?

      再举一个类似的例子:你可以用同样的方式问吗?
      为什么要在 Web 开发中使用多层架构? 只需将所有内容放在一个服务器上,它就会快很多,因为查询 UI 数据的后端和所有层或查询远程数据库等的网络延迟不会有延迟。
      当然,你说得有道理。但是然后问问你自己,这可以随着负载的增加而扩展吗?答案是不。那么可扩展性对您来说很重要,还是您想保持“将所有东西放在一个服务器中”的想法?如果您的收入来自电子网站,那么您无法为更多客户提供服务这一事实不会仅仅因为您为前 100 名客户提供的服务非常快而让您的客户满意......无论如何这是我的看法

      【讨论】:

      • 我根本不打算质疑 OOP 的优点。我只是想知道这就是全部:)
      • 如前所述,我并没有声称要直接解决您的问题。我只是想向您展示我所理解的是 您的观点的不同观点。除非我没有得到你的想法,我的回答完全断章取义(所以我在这种情况下道歉)
      • 别担心,当然,我已经知道你所说的大部分内容,但我感谢你投入的时间和精力,毫无疑问,你的帖子最终会对社区有用:)
      猜你喜欢
      • 2011-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-24
      • 2022-11-01
      • 1970-01-01
      • 2017-06-11
      相关资源
      最近更新 更多