非面向对象编程中多态性的替代方案



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

我想知道程序员将如何处理目前通常通过多态性解决的问题,即遍历不相同的元素集合,并在不同的对象之间调用通用功能。

想到的一种方法是使用一个结构,该结构具有指向适当函数的函数指针(或函数指针数组中的索引)以及指向实际实例的void指针,并将指针传递给函数中的适当类型。但我就是这样做的——一个对这个问题一无所知的人

我确实意识到这可能是一个棘手的问题,但由于我在"旧"时代没有出现过,我真的很想知道这个问题是如何解决的。在过程编程中使用了什么样的方法,它是否有性能优势,因为我们都知道,由于虚拟方法查找,即使在C++等快速语言中,多态性也会有开销。

一个非常简单的例子。

如果你对此感兴趣,你可以在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;                                                                   
}  

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

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

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

这不是对您的示例的直接回答,而是对您的评论的回应,这显示了错误的视角IMHO

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

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

另一方面,旧的"程序化"方式也有客观的优点;它的代码"简单"(无需考虑如何设计系统,只需将所有内容放在主要位置),并且在许多方面的开销较小(由于需要更少的类和更紧凑的对象,所以内存开销较小-不需要虚拟表等-方法调用较少,所以性能可能更好,动态绑定没有性能开销-不管现在的开销是多少…-)

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

因此,在某些情况下,C/C++中的真正优秀的程序员可以按照你所说的"旧方法"进行编程,但它为这个特定程序带来的性能优势值得吗?

举另一个类似的例子:你可以用同样的方式提问吗
为什么在web开发中使用多层体系结构只需将所有内容放入一台服务器,速度就会快得多,因为在查询后端和所有层的UI数据时不会有延迟,也不会有查询远程数据库等的网络延迟。
当然,你说得有道理。但问问你自己,这种规模会随着负荷的增加而扩大吗?答案是否定的。那么可伸缩性对你来说很重要吗?还是你想保持"把所有东西都放在一台服务器上"的想法?如果你的收入来自电子网站,你不能为更多的客户提供服务这一事实不会让你的客户感到高兴,因为你很快就服务了前100名客户。。。无论如何,这是我的看法

相关内容

  • 没有找到相关文章

最新更新