我想说,如果你想硬编码这种行为,你最好不要使用面向对象的编程。只需将其实现为调用其他函数的函数。
(我理解的“那种行为”:如果foo2
从被称为 as 的代码内部调用super#foo1
,那么foo2
应该调用超类的实现,而不是来自子类的更“具体”的实现)
这是最简单、最干净、最清晰的方法:按照您的意愿编写函数。
或者您应该向自己和我们解释:为什么需要 OOP?问题文本中没有给出原因。为什么使用 makefoo1
和foo2
方法而不是独立的函数?(除了foo1
and foo2
,你的程序中可能有一些对象、类和方法,如果合适的话)。
想知道这个问题是否来自与其他语言的比较
如果您知道另一种 OO 语言,那么您希望 OOP 中的“那种行为”很奇怪:这不是 Java 或 C++ 中所期望的行为,因为它们采用与每个对象相关联的虚拟方法表的概念运行时,因此当在程序中调用方法时,它会在运行时分派到与对象实际关联的该方法的实现。因此,简而言之:每当您在程序中使用方法调用表达式时,您就承诺遵循这一原则,即找到方法的实现(“后期绑定”),正如 gasche 所指出的那样。虽然仍然比较。OCaml 与使用 Niki Yoshiuchi 指出的虚拟方法表实现的语言之间的差异。
将所有可用和想要的行为的讨论形式化
尽管您想要的可能不是许多流行的 OO 语言中的预期和可用行为,但如果可以访问 OOP 实现内部,它是可以想象的并且可以在某些特定的 OOP 系统中实现。
说,如果在某些实现中,super
是一个保存超类的方法表的结构(在解决当前对象的方法调用时回退到),并且方法是必须接收对象(方法表)作为第一个的函数arg,然后执行你想要的,一个人会写super.foo1(super, y)
.
(我实际上想知道是否有 OOP 实现的内部结构暴露给程序员并允许进行这样的调用。)
而通常的 OOP 行为将在此系统中表示为(当前对象的方法表在this.foo1(this, y)
哪里。)this
您的 OCaml 调用super#foo1 y
或 Java会将super.foo1(y);
这个“我的”系统转换为super.foo1(this, y)
. (尽管仍然可以参见 Niki Yoshiuchi 指出的 OCaml 与使用虚拟方法表实现的 Java 等语言之间的差异。)
您会看到这 3 种情况之间的差异。
附录。寻找可以以这种方式工作的语言
嗯,PHP 可能是一种可以实现这种行为的语言,但是:
- 仅在“类级”编程(静态方法)上,而不是对象级;
- 仅当您在函数调用中硬编码一些奇怪的“后期静态绑定”时:
#!/usr/bin/php
<?php
class Foo {
public static function foo1($y) {
echo "foo1\n";
static::foo2($y-1);
}
public static function foo2($y) {
echo "foo2\n";
if ($y > 0)
static::foo2($y);
else
echo "end\n";
}
}
class Bar extends Foo {
public static function foo2($y) {
echo "bar2\n";
if ($y > 0)
Foo::foo1($y);
else
echo "endbar\n";
}
}
class Model extends Foo {
public static function foo2($y) {
echo "model2\n";
if ($y > 0)
static::foo1($y);
else
echo "endmodel\n";
}
}
Model::foo2(3);
Bar::foo2(3);
?>
从某种意义上说,模型的行为类似于具有虚拟方法的标准 OO 对象,以及您想要的 Bar :
$ ./test-force-super-binding.php | 头 -20
模型2
foo1
模型2
foo1
模型2
foo1
模型2
终端模型
酒吧2
foo1
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
$
(顺便说一句,使用parent::
而不是Foo::
不会让我们达到您想要的行为。)
我不明白疯狂的 PHP 绑定规范的目的,例如static::
,它们仅对静态方法(即类级编程)有一些影响。
默认情况下,类似的 C++ 示例不提供 OO 对象级行为:
#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 | 头-10
酒吧2
foo1
foo2
foo2
foo2
foo2
foo2
foo2
foo2
foo2
$
即使在代码中的函数调用中没有任何特殊限定符 for Bar::foo2()
,所以对我们来说并不有趣。
Java 的静态方法呢?..(它们是否与 C++ 不同,并且默认为我们提供了类似虚拟方法的函数调用解析?)