我目前正在设计一种编程语言,我很好奇如何解决这个问题:
假设我有一个如下所示的类(或接口)A:
class A { // size is 4 bytes
int32 a = 0;
}
和第二个 B 类扩展它,看起来像这样:
class B extends A { // size is 8 bytes
int32 b = 0;
}
并且我有一个看起来像这样的函数 f:
int32 f(A first, A second) {
return first.a + second.a;
}
但是,如果我用两个 B 调用它,则 second.a 不会与用两个 As 调用它位于同一位置,因为第一个参数会移动它。我目前解决这个问题的想法是:
- 不允许未知大小的参数,并强制它作为指针或引用传递(我认为这就是 Rust 所做的)
- 将以下所有信息写入调用堆栈:指向第二个的指针、指向第二个之后的指针、非可变大小参数、第一、第二
- 为 first 和 second 的每个可能大小创建一个函数,并确定在编译时(如果已知)或在运行时使用 vtables 调用哪个函数。
第二个想法将是一个问题,因为它需要得到所有函数的支持,即使它们很少或从不使用子类型调用,这是低效的。
第三个想法需要创建很多函数(一个接受 5 个参数的函数,这些参数可以是 20 种不同的子类型,如果只调用一个具有未知类型参数的函数,则需要生成 100 段类似的代码),并且对于只有一个函数使用它的每个类,都需要一个 vtable。此外,已编译库中的函数不能与新子类型一起使用。
结合 2 和 3 并创建相同函数的两个版本,一个只接受类型,另一个也接受子类型可以解决其中一些问题。
我很好奇是否有更好的解决方案,以及 C++ 等其他语言如何实现这一点。