Oop 如何强制只调用超类';s方法,尽管它们已被重写(在Ocaml中)
老实说,我不太了解OCaml的对象系统。以下代码片段说明了我的问题:Oop 如何强制只调用超类';s方法,尽管它们已被重写(在Ocaml中),oop,ocaml,overriding,late-binding,Oop,Ocaml,Overriding,Late Binding,老实说,我不太了解OCaml的对象系统。以下代码片段说明了我的问题: class foo = object (o) method foo1 y = print_endline "foo1"; o#foo2 (y - 1) method foo2 y = print_endline "foo2"; if y > 0 then o#foo2 y else print_endline "end" end class b
class foo =
object (o)
method foo1 y =
print_endline "foo1";
o#foo2 (y - 1)
method foo2 y =
print_endline "foo2";
if y > 0 then o#foo2 y else print_endline "end"
end
class bar =
object (o : 'self_type)
inherit foo as super
method foo2 y =
print_endline "bar2";
if y > 0 then super#foo1 y else print_endline "endbar"
end
let _ = (new bar)#foo2 3
执行时,代码段将生成以下输出:
bar2
foo1
bar2
foo1
bar2
endbar
,显示超类方法foo1(通过super#foo1调用)从子类执行重写的方法foo2。相反,我希望它从超类调用方法foo2,因为它是通过super调用的
是否有可能实现这种行为,即让一个超类方法只调用其他超类方法,即使它们在子类中被重写?对此我不是100%确定,但我很确定您不能。在OCaml中,继承和子类型是两个不同的概念。类可以是另一种类型的子类型,而不需要继承。继承所做的一切就是从继承的类中拉入方法
多态是通过结构类型实现的,所以您对
inherit…as…
语法区分重写方法和继承方法的方法。在您的示例中的bar
中,o#foo1
和super#foo1
是相同的方法(因为bar
不实现foo1
),而o#foo2
和super#foo2
是不同的方法。尽管如此,我认为继承的类无论如何都无法知道它已被继承,也无法区分它的方法和被重写的方法。这可能有一些语法,但我非常怀疑,因为继承和多态性是独立的概念。不,不是。这是“后期绑定”,是OO的一个基本概念,不是OCaml特有的
我不知道你想做什么,但面向对象编程可能不是正确的工具,或者至少不是那样使用的。如果你想学习OCaml,你可能应该专注于非面向对象的部分,这对于一开始来说已经足够有趣了。我想说,如果你想硬编码这种行为,最好不要使用面向对象编程。只需将其实现为调用其他函数的函数 (“我所理解的那种行为:如果从被称为
super#foo1
的代码内部调用foo2
,那么应该调用超类实现中的foo2
,而不是子类中更“具体”的实现)
这是最简单、最干净、最清晰的处理方式:编写能满足您需求的函数
或者你应该向自己和我们解释:为什么你需要OOP?问题文本中没有给出原因。为什么要使用foo1
和foo2
方法而不是独立的函数?(除了foo1
和foo2
,您的程序中可能有一些对象、类和方法(如果适用)
想知道这个问题是否来自与其他语言的比较
如果你知道另一种面向对象语言,那么你想从OOP中得到“那个行为”是奇怪的:它不是java、C++中所期望的行为,因为它们使用了一个虚拟方法表的概念,它在运行时与每个对象相关联,因此在程序中调用方法时,它在运行时被调度到实际与对象关联的方法的实现中。因此,简言之:每当您在程序中使用方法调用表达式时,您都会遵循这个原则,即找到方法的实现(“后期绑定”),正如gasche所指出的那样。尽管仍然参考Niki Yoshiuchi指出的OCaml和使用虚拟方法表实现的语言之间的差异
将所有关于可用和想要的行为的讨论形式化 尽管在许多流行的OO语言中,您想要的可能不是预期的和可用的行为,但是如果您能够访问OOP实现内部,它是可以想象的,并且可以在某些特定的OOP系统中实现 比如说,如果在某些实现中,super
是一个保存超类的方法表的结构(在解析当前对象的方法调用时要回退),并且这些方法是必须接收对象(方法表)作为第一个参数的函数,那么要执行您想要的操作,可以编写super.foo1(超级,y)
(实际上,我想知道是否有OOP实现的内部结构向程序员公开,并且允许进行这样的调用。)
而在这个系统中,通常的OOP行为将通过this.foo1(this,y)
来表示(其中this
是当前对象的方法表)
您的OCaml调用super#foo1y
或Javasuper.foo1(y)
将此“我的”系统转换为super.foo1(this,y)
(尽管仍然是Niki Yoshiuchi指出的OCaml与使用虚拟方法表实现的Java等语言之间的差异)
你可以看到这三种情况之间的区别
附录。寻找这样的语言
嗯,PHP可能是一种可以实现这种行为的语言,但是:
- 仅在“类级”编程(静态方法),而不是对象级
- 只有在函数调用时硬编码一些奇怪的代码时:
Bar::foo2()
的代码中的函数调用中没有任何特殊的限定符,对fo也不感兴趣
$ ./test-force-super-binding.php | head -20
model2
foo1
model2
foo1
model2
foo1
model2
endmodel
bar2
foo1
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
$
#include<iostream>
class Foo {
protected:
static void foo1(int y) {
std::cout << "foo1" << std::endl;
foo2(y-1);
}
public:
static void foo2(int y) {
std::cout << "foo2" << std::endl;
if (y > 0)
foo2(y);
else
std::cout << "end" << std::endl;
}
};
class Bar: public Foo {
public:
static void foo2(int y) {
std::cout << "bar2" << std::endl;
if (y > 0)
foo1(y);
else
std::cout << "endbar" << std::endl;
}
};
int main() {
Bar::foo2(3);
return 0;
}
$ ./a.out | head -10
bar2
foo1
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
$