假设我们有一个具有不同元素的绘图程序,如圆形、矩形、三角形等。不同类型的对象都需要类似的功能,如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名客户。。。无论如何,这是我的看法