假设我们有一个包含不同元素的绘图程序,例如圆形,矩形,三角形等。不同种类的对象都需要类似的功能,如draw()
来展示自己。
我想知道程序员如何处理现在通常由多态性解决的问题,即通过一组不相同的元素并在不同的对象之间调用通用功能。
想到的一种方法是使用一个带有函数指针的结构,该函数指针指向适当的函数(或函数指针数组中的索引)以及指向实际实例的void指针,并将指针转换为正确的类型在功能中。但这就是我 - 一个对这个问题毫无头绪的人会这样做。
我确实意识到这可能是一个愚蠢的问题,但由于我在“过去”的日子里没有出现过,我真的很想知道这个问题是如何解决的。在程序编程中使用了什么样的方法并且它具有性能优势,因为我们都知道多态性即使在像C ++这样的快速语言中也有开销,这是由于虚方法查找。
在诸如C的过程语言中,这将通过为每个自定义数据类型(可能表示为结构)定义draw()
函数的单独实现来解决。任何通用功能都将被分解为一个单独的函数,该函数对每个结构的共享元素进行操作(例如对象中心的x和y坐标,它们将出现在每个结构中)。从代码和功能的角度来看,这与使用多态的OOP布局没有太大区别,在这种布局中,您仍然必须在基类中实现共享的draw()
方法并在特定的子类中覆盖它。在过程语言的情况下,我们不会将这些函数定义拆分为单独的“对象”。
有一些奇特的方法可以从过程语言中获取类似对象的行为,例如联合类型或带有额外布尔值的单个整体类型,以确定是否正在使用特定元素。这将允许您编写单个draw()
函数,该函数可以根据启用的元素执行逻辑切换。在实践中,我唯一看到的地方是基于CORBA的系统,其中用C编写的程序必须模仿通过IDL传播的OOP语言的一些行为(即将Java对象转换为构造,可以解码成C风格的结构)。
至于使用C ++和Java等语言进行虚拟方法查找的开销,这是面向对象语言无法完全避免的。通过正确使用final
关键字(允许编译器/ JVM优化方法查找表)可以很好地减轻它。
这不是你的例子的直接答案,而是你的评论的地址,这显示了错误的观点恕我直言
我只是想知道那个特定的问题,如果有一种更有效的方法可以避免虚拟方法的性能开销,那么我感兴趣
这里有一些东西可以理解。一切都有权衡。设计模式和OO具有我们已经喜爱的所有已知优点,但也有缺点,例如太多的类,内存开销,由于许多方法调用等导致的性能开销
另一方面,旧的“程序化”方式也具有一定的客观优势;代码“简单”(无需考虑如何设计系统,只需将所有内容放在main中)并且在许多方面具有较少的开销(较少的内存开销,因为需要较少的类和更紧凑的对象 - 不需要虚拟表etc-和更少的方法调用所以可能更好的性能,没有动态绑定的性能开销 - 无论如何,无论如何......-)。
但这不是特定问题实例的权衡取舍,而是经验表明构建软件的正确方法是什么。重复使用模块化代码并协助单独测试(质量保证),可读,可维护,灵活扩展,这些属性已被充分理解,应该是软件开发的主要驱动因素。
所以在某些情况下,一个真正优秀的C / C ++程序员可以按照你说的那样“老方式”,但是这个特定程序带来的性能优势值得没有人能够维护或者之后还能维持吗?
举一个类似的例子:你可以用同样的方式问? 为什么Web开发中的多层体系结构?只需将所有内容放入一台服务器中它就会变得更快,因为查询后端和UI的数据的所有层或远程数据库查询的网络延迟等都没有延迟。 当然,你有一个观点。但是问问你自己,这种规模可以随着负荷的增加而增加吗?答案是不。那么可扩展性对您来说很重要,或者您希望保持“将所有内容放在一个服务器中”的想法?如果你的收入来自电子网站,那么你无法为更多客户提供服务这一事实不会让你的客户感到满意只是因为你真的很快就服务了前100 ...不管这是我的看法
一个非常简单的例子。
如果您对此感兴趣,可以在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;
}