Как заставить называть только методы Superclass, несмотря на то, что они были переопределены (в OCAML)

StackOverflow https://stackoverflow.com/questions/4829597

Вопрос

Честно говоря, я не знаю много о объектной системе 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 ++ и дают нам виртуальное метод, подобное разрешению функций по умолчанию?)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top