Законно ли расширять класс класса? - PullRequest
5 голосов
/ 10 апреля 2010

Я писал систему, которая во время выполнения генерирует несколько шаблонов, а затем генерирует некоторые объекты на основе этих шаблонов. У меня была идея, что шаблоны могут быть расширениями класса Class, но это привело к некоторым великолепным ошибкам:

VerifyError: Error #1107: The ABC data is corrupt, attempt to read out of bounds.

Что мне интересно, так это то, возможно ли даже создание подкласса Class, если есть какой-то случай, когда это целесообразно, а не просто грубое злоупотребление ООП. Я считаю, что это должно быть возможно, так как ActionScript позволяет создавать переменные типа Class. Это использование описано в записи LiveDocs для Class , но я не видел упоминаний о подклассе Class.

Вот пример псевдокода:

class Foo extends Class

var A:Foo = new Foo(); // A is a class
trace(A is Class); // true, right?
var b = new A(); // b is an instance of class A

Я понятия не имею, какой будет тип b. Было бы это?

trace(b is A); // true?

Но тогда, не могли бы вы ввести переменную b для ввода A, как в var b:A = new A();, даже если A не существует до времени выполнения? Я читал, что это невозможно, поскольку A не является статически разрешимым, но я делаю свои собственные тесты, чтобы изучить эту возможность.

В конечном итоге цель состоит в том, чтобы генерировать новые классы во время выполнения , а затем создавать экземпляры этих классов.

В итоге: вы можете создать подкласс класса Class? Если это так, как вы можете сделать это без ошибок, и какой тип экземпляров экземпляров подкласса класса?

Ответы [ 2 ]

5 голосов
/ 11 апреля 2010

Начиная с элемента liveoc в первом абзаце: Every Class object is an instance of the Class class. Поэтому было бы ошибкой расширять класс, поскольку любой объект класса уже является классом.

Вы сказали a system that generates some templates, and then generates some objects based on those templates. Похоже, что вы действительно пытаетесь сделать, это создать интерфейс.

Интерфейс должен использоваться, когда ваш шаблон не обеспечивает никакой реализации. То есть вы объявляете кучу полей и методов, но не предоставляете реализацию методов. Вы объявите такой класс следующим образом:

public interface Foo {
    function bar:void;
}

Теперь, чтобы создать класс, который реализует этот интерфейс, вы просто делаете следующее.

public class MyClass implements Foo {
    function bar:void {
        ..... implementation goes here .....
    }
}

Для класса возможно реализовать несколько интерфейсов, в то время как он может расширять только один класс.

Если, однако, вы хотите предоставить какую-либо реализацию в своем шаблонном классе, то, скорее всего, вам лучше всего просто создать класс, который имеет все сходства с его подклассами, и просто использовать простое старое наследование.

Надеюсь, это поможет.

1 голос
/ 12 апреля 2010

Вот результаты моего собственного углубленного исследования:

Расширение класса Class, по сути, невозможно, хотя это нигде не документировано, что я еще не видел. Из моего исследования я теперь убежден, что сам класс Class не включает в себя все качества, которыми обладают другие классы верхнего уровня, хотя все они, как говорят, выходят из класса Object.

Еще одним разочарованием является тот факт, что создание подклассов различных классов верхнего уровня приведет к нескольким различным сообщениям об ошибках, что затруднит определение проблем. Начнем с простого примера: если вы попытаетесь создать подкласс многих примитивных типов данных ActionScript (int, uint, Number, String, Boolean и т. Д.), Вы получите следующую ошибку compiler :

1016: Base class is final.

Это имеет смысл, потому что просмотр документов для любого из этих классов показывает, что они действительно окончательные:

Package       Top Level
Class         public final class Boolean
Inheritance   Boolean -> Object

Последнее слово, конечно, означает, что другой класс не может расширять класс, помеченный как final . Теперь для более сложного примера, давайте посмотрим на расширение класса Function. Класс Function не является окончательным, согласно документам. Поскольку это не является окончательным, означает ли это, что мы можем расширить класс Function для создания наших собственных специализированных функциональных объектов? Вот определение:

class MyFunction extends Function { /*...*/ }

.. а затем в время выполнения :

VerifyError: Error #1103: Class ::MyFunction cannot extend final base class.

Сравните это с ошибкой примитивного типа данных выше. Эта ошибка произошла во время компиляции, поскольку унаследованный примитивный класс был фактически помечен как финальный. Класс Function не помечен как финальный, но класс продолжает вести себя так, как если бы он был, только во время выполнения.

Теперь мы подошли к основной проблеме: расширению класса Class. Как и в случае с классом Function, класс Class не является окончательным. Кроме того, класс Class является динамическим, то есть новые свойства могут быть добавлены к объекту Class во время выполнения.

В качестве интересного дополнения: класс Function также является динамическим, и я полагаю, что эта часть обеспечивает постоянную поддержку старых механизмов наследования прототипов, присутствующих в диалекте ECMAscript. На этом диалекте функции используются как своего рода классы (ну, в общем, прототипы), а способность функций добавлять свойства во время выполнения является частью возможности наследования прототипов.

Теперь, насколько я понимаю, свойства объекта Class такие же, как статические свойства, доступные для любого экземпляра этого класса. Таким образом, должно иметь логический смысл, что кто-то может захотеть манипулировать объектом Class во время выполнения, позволяя ему изменить поведение этого класса и его экземпляров. То, что класс Class является динамическим, усиливает это представление.

Поскольку класс Class не является окончательным, мне было любопытно посмотреть, можно ли расширить класс Class, создать собственную специализацию модели Class и работать где-нибудь в области метаязыка. Я оставлю на следующий день обсуждение того, почему кто-то хотел бы сделать это, и какую власть это предположительно допустило бы. Теперь для заключительного примера, давайте расширим класс Class. Вот определение:

// the definition causes no errors on its own, even though the compiler "sees" it
class MyClass extends Class { /*...*/ }

/* elsewhere */

MyClass; // the only mention of MyClass beyond the definition

.. а затем в время выполнения :

verify global$init()
                    stack:
                    scope: 
                     locals: global 

/* snip about 120 lines */

   46:getlex 34
                    stack: global Class$?
                    scope: global Object$ Class$ 
                     locals: global 
   48:newclass MyClass$cinit()
VerifyError: Error #1107: The ABC data is corrupt, attempt to read out of bounds.

    at global$init()

Святая трассировка стека! VerifyError зарезервировано для искаженных данных SWF. Исходя из того, что я мог найти, это также, как «ошибка» во Flash Player имеет тенденцию проявляться. В любом случае это немного выходит за рамки обычной ошибки ActionScript.

На данный момент довольно трудно понять, что именно происходит, но это то, что я смог до сих пор сделать вывод.

VerifyError: Error #1107: The ABC data is corrupt, attempt to read out of bounds.

Я (ошибочно, см. Ниже комментарий) считаю, что «ABC» обозначает Абстрактный базовый класс, который является термином, применяемым к классам, которые не могут быть созданы, только расширены. Однако вышеуказанная ужасающая ошибка возникает не в момент создания, а при первом доступе к подклассу класса MyClass. Фактически, в коде примера я никогда не создаю экземпляр объекта MyClass, я ссылаюсь только на сам класс MyClass.

Я провел еще несколько тестов и обнаружил, что объекты Class, по-видимому, не имеют конструкторов, по крайней мере, того типа, который обычно происходит из подклассов Object. Просто набрав new Class(); в любом месте вашего кода, это наглядно продемонстрирует этот факт, но вы можете исследовать это далее, проверив свойство .constructor и другие приемы. В результате этого экземпляры класса Class в лучшем случае являются объектами второго класса, поскольку они не могут быть созданы во время выполнения.

Сначала я подозревал, что это была точная причина моего противного VerifyError. Однако теперь я считаю, что существует много других элементов класса, невидимых для нашего собственного кода ActionScript, которые могут существовать или не существовать в классе Class, классе Function или других любопытных местах. Конечно, когда Flash Player пытается получить доступ к одному из необходимых для расширения базового класса, и он не существует (поскольку Class, возможно, является ABC, поэтому отсутствуют некоторые элементы, присутствующие в обычном классе), можно ожидать увидеть за пределами VerifyError.

Таким образом, расширение класса теперь выглядит невозможным. Может показаться, что класс Class не включает в себя все качества, которые большинство других классов верхнего уровня наследуют от Object, хотя это сложно проверить.

Я бы предпочел видеть более конкретное сообщение об ошибке в результате расширения класса, но в данный момент такой вещи нет. Мне бы хотелось, чтобы некоторые возможности метапрограммирования вернулись к ActionScript. Пока достаточно знать, что это невозможно сделать, по крайней мере, таким образом.

...