Как заставить называть только методы Superclass, несмотря на то, что они были переопределены (в OCAML)
-
26-10-2019 - |
Вопрос
Честно говоря, я не знаю много о объектной системе 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 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
, показывая, что метод SuperClass FOO1 (вызываемый через Super#FOO1) выполняет метод переопределения FOO2 из подкласса. Вместо этого я бы ожидал, что он вызовет метод FOO2 из SuperClass, как он называется через Super.
Можно ли достичь такого поведения, т.е. есть суперклассионный метод, вызывая только другие методы суперкласса, даже если они переопределены в подклассе?
Решение
Я не уверен на 100% в этом, но я уверен, что вы не можете. В наследстве и подтинке есть две разные понятия. Класс может быть подтипом другого типа без наследования. Все наследство - это привлечение методов из наследственного класса.
Полиморфизм достигается за счет структурного типирования, поэтому ваш призыв к foo2
вызывает метод в bar
потому что bar
реализовано foo2
и не потому, что bar
наследует от foo
(Как следует сказать, C ++, где bar#foo2
называется из -за виртуальной таблицы функций, поиск вверх).
Тем не менее, OCAML предоставляет вам способ различить переопределенные методы и унаследованные методы с использованием inherit...as...
синтаксис. В bar
Из вашего примера, o#foo1
а также super#foo1
тот же метод (поскольку bar
не реализует foo1
) тогда как o#foo2
а также super#foo2
разные методы. Несмотря на это, я не думаю, что в любом случае есть унаследованное класс, чтобы знать, что он был унаследован и различает его методы и переопределенные методы. Для этого может быть какой -то синтаксис, но я очень сомневаюсь в этом из -за того, что наследование и полиморфизм являются независимыми понятиями.
Другие советы
Нет, это не так. Это «позднее обязательство», основная идея OO, не специфичная для OCAML.
Я не знаю, что вы пытаетесь сделать, но объектно-ориентированное программирование, возможно, не правильные инструменты или, по крайней мере, не используется таким образом. Если вы хотите выучить OCAML, вы, вероятно, должны сосредоточиться на нео-деталях, что достаточно интересно для начала.
Как указывает Гаше, это предполагаемое и стандартное поведение для языков OO.
А super#foo1
Позвони, с тех пор bar
не переопределяет foo1
, точно эквивалентно o#foo1
. Анкет А super
конструкция существует только для того, чтобы иметь возможность назвать foo2
метод foo
Из методов в bar
(В противном случае нет способа ссылаться на этот метод). В foo1
как называется из bar#foo2
, o
на самом деле bar
, не foo
, так что вызывая foo2
Метод вызывает bar
foo2
метод
Я бы сказал, что если вы хотите жестко кодировать это поведение, вам лучше не использовать объектно-ориентированное программирование. Просто реализуйте его как функции, вызывающие другие функции.
(«Такое поведение», как понято мной: если звонить foo2
изнутри кода, который был назван как super#foo1
, тогда именно foo2
Из реализации суперкласса следует называться, а не из более «конкретных» реализаций из подклассов)
Это самый простой, самый чистый и самый четкий способ продолжения: программные функции, которые делают то, что вы хотите.
Или вы должны объяснить себе и нам: зачем вам ООП? Причина этого не приведена в тексте вопроса. Зачем делать foo1
а также foo2
Методы, а не независимые функции? (Помимо foo1
а также foo2
, У вас могут быть некоторые объекты, классы и методы в вашей программе, где это необходимо).
Интересно, возникает ли этот вопрос из сравнения с другими LNAGUGE
Если вы знаете другой язык OO, это странно, что вы хотите «поведение» от ООП: это не то поведение, которое, скажем, в Java или C ++, потому что они используют концепцию таблицы виртуальных методов, связанных с каждым объектом в Время выполнения, поэтому при вызове метода в вашей программе он отправляется во время выполнения для реализации этого метода, фактически связанного с объектом. Итак, короче говоря: Всякий раз, когда вы используете выражение, вызывающее метод в своей программе, вы посвятите себя этому принципу внедрения реализации метода («позднее обязательство»), как указал Гаше. Хотя все еще ср. Различия между OCAML и языками, реализованными с помощью таблицы виртуальных методов, указанных Ники Йошиучи.
Формализация всего обсуждения доступного и желательного поведения
Хотя то, что вы хотите, не может быть ожидаемым и доступным поведением во многих популярных языках ОО, оно только можно было реализовать в некоторых конкретных системах ООП, если у кого есть доступ к внутренним внутренним показателям внедрения ООП.
Скажем, если в какой -то реализации, super
Является ли структура, содержащая таблицу методов суперкласса (чтобы отступить при разрешении метода вызовов для текущего объекта), а методы - это функции, которые должны получать объект (таблица методов) в качестве 1 -й ARG, затем выполнить то, что вы Хочу, можно было бы написать super.foo1(super, y)
.
(Я действительно задаюсь вопросом, есть ли реализации ООП, внутренние внутренности, которые подвергаются программисту и позволяют выполнять такой вызов.)
Тогда как обычное поведение ООП будет выражено в этой системе this.foo1(this, y)
(куда this
Таблица методов для текущего объекта.)
Ваш звонок OCAML super#foo1 y
или Java super.foo1(y);
переводится на эту «мою» систему как super.foo1(this, y)
. Анкет (Несмотря на то, что он все еще CF. Различия, указанные Ники Йошиучи между 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 с виртуальными методами и стержень как Вы хотели:
$ ./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 $
(Кстати, используя parent::
вместо Foo::
Не приведет нас к желаемому поведению.)
Я не понимаю, как привязанность безумных спецификаций связывания PHP, таких как static::
, которые имеют некоторый эффект только для статических методов (т.е. программирование на уровне класса).
Аналогичный пример C ++ не дает поведение на уровне объекта по умолчанию:
#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 $
Даже без какого -либо специального квалификатора при вызове функций в коде для Bar::foo2()
, так что не интересно для нас.
Как насчет статических методов Java? .. (они отличаются от C ++ и дают нам виртуальное метод, подобное разрешению функций по умолчанию?)