当我们有两个类时:
class Foo {
void foo() {
System.out.println("foo");
}
}
Run Code Online (Sandbox Code Playgroud)
和:
class Bar extends Foo{
void bar() {
System.out.println("bar");
}
}
Run Code Online (Sandbox Code Playgroud)
Bar clazz 对象是否在 vtable 中存储对 foo() 和 bar() 方法的引用,或者仅在 Bar 的 vtable 中存储对 bar() 方法的引用并访问 foo() 方法 jvm 访问 Bar clazz 对象,然后访问 Foo clazz 对象,然后在其 vtable 中找到 foo() 方法?是不是更像这样:
或者那个:
或者也许这没有在规范中描述并且可以依赖于 JVM 实现?
在Ada中,类型T的原始操作只能在定义了T的包中定义.例如,如果Vehicules包定义Car并Bike标记了记录,两者都继承了一个通用的Vehicle抽象标记类型,那么Vehicle'Class必须在此Vehicles包中定义除了可以在类范围类型上调度的所有操作.
假设您不想添加基本操作:您没有编辑源文件的权限,或者您不希望使用不相关的功能来混淆包.
然后,您无法在其他包中定义隐式分派类型的操作Vehicle'Class.例如,你可能想序列车辆(定义一个Vehicles_XML与封装To_Xml调度功能)或显示它们作为UI元素(定义一个Vehicles_GTK与包Get_Label,Get_Icon...调度功能)等来执行动态调度的唯一方法是写代码明确; 例如,里面Vechicle_XML:
if V in Car'Class then
return Car_XML (Car (V));
else
if V in Bike'Class then
return Bike_XML (Bike (V));
else
raise Constraint_Error
with "Vehicle_XML is only defined for Car and Bike."
end if;
Run Code Online (Sandbox Code Playgroud)
(Vehicles当然,在其他地方定义并在其他地方使用的访问者模式也可以工作,但是仍然需要相同类型的显式调度代码.编辑实际上没有,但是仍然有一些样板代码要编写)
我的问题是:
是否有理由限制在T的定义包中定义在T上动态调度的操作?
这是故意的吗?这背后有一些历史原因吗?
谢谢
编辑:
感谢您当前的答案:基本上,它似乎是语言实现的问题(冻结规则/虚拟表).
我同意编译器会随着时间的推移逐步开发,并且并非所有功能都能很好地适应现有工具.因此,在一个独特的包中隔离调度操作符似乎是一个主要由现有实现而不是语言设计引导的决策.C++/Java系列之外的其他语言提供了没有这种要求的动态调度(例如OCaml,Lisp(CLOS);如果重要的话,那些也是编译 …
怎么可能使这段代码工作?
据我所知,Scala 没有动态调度(类似于 Java)。是否可以以某种方式模拟动态调度?
或者最好的解决办法是什么?
object Tezt {
case class SuperClazz()
case class SubClazz1() extends SuperClazz
case class SubClazz2() extends SuperClazz
def method(obj: SubClazz1) = {
// stuff
}
def method(obj: SubClazz2) = {
// stuff
}
def func[T <: SuperClazz](obj: T) = {
Tezt.method(obj) // Error: Cannot resolve method reference with such signature
}
}
Run Code Online (Sandbox Code Playgroud) types scala type-inference multiple-dispatch dynamic-dispatch
我从Java转到Go,有些事情使我感到困惑。
例如,让我们考虑以下代码:
package main
import (
"fmt"
)
type I interface {
Do()
MegaDo()
}
type A struct {
}
func (a *A) Do() {
fmt.Println("A")
}
func (a *A) MegaDo() {
a.Do()
}
type B struct {
A
}
func (a *B) Do() {
fmt.Println("B")
}
var i I
func main() {
fmt.Println("Hello, playground")
var i I = &B{}
i.MegaDo()
}
Run Code Online (Sandbox Code Playgroud)
这里我们有一个I方法Do()和接口MegaDo()。Struct A既实现方法又实现内部MegaDo调用Do。而B由以上A,仅覆盖Do() …
如果我在下面的代码中创建c1类型Concrete1,是否有任何运行时开销?
pub trait ExampleTrait {
fn foo(&self);
}
pub struct Concrete1 {}
impl ExampleTrait for Concrete1 {
fn foo(&self) {}
}
pub struct Concrete2 {}
impl ExampleTrait for Concrete2 {
fn foo(&self) {}
}
fn main() {
let c1 = Concrete1 {};
c1.foo();
}
Run Code Online (Sandbox Code Playgroud)
这是否需要任何类型的 v 表查找或任何其他类型的开销?我想要一个特征,以便我可以在编译时强制执行Concrete1并Concrete2实现相同的方法集。
我将静态选择在主程序中使用哪种具体类型;这两个实现的存在只是为了在需要时我可以使用 trait 的替代实现。
假设我有以下结构
trait T{}
struct A<X:T>{
...
}
Run Code Online (Sandbox Code Playgroud)
我想知道这样的事情是否可能
Box<A<dyn T>>
Run Code Online (Sandbox Code Playgroud)
目前我收到错误
trait T{}
struct A<X:T>{
...
}
Run Code Online (Sandbox Code Playgroud)
但是当我添加
trait T:Sized{}
Run Code Online (Sandbox Code Playgroud)
我明白了
Box<A<dyn T>>
Run Code Online (Sandbox Code Playgroud)