кастинг между классами братьев и сестер, AS3

У меня есть два класса, derivedClassA и derivedClassB, которые оба расширяют parentClass. Я объявляю var o:parentClass, а затем, в зависимости от того, что происходит, я хочу привести o к типу derivedClassA или derivedClassB.

По сути, это:

var o:parentClass  

...  

if(shouldUseA)  
    o = new derivedClassA();  
else  
    o = new derivedClassB();  
o.doSomething();

Но это не работает, я получаю все виды ошибок. Разве не так работает наследование классов? Я чувствую, что мне не хватает чего-то действительно фундаментального, но я не могу понять, что. Должен ли я вместо этого использовать интерфейсы? Есть ли другой способ сделать то, что я хочу?

РЕДАКТИРОВАТЬ ДЛЯ ПОЯСНЕНИЯ:
- doSomething() определено в parentClass как общедоступное, а в производных классах как override public function doSomething()
- ошибки, которые я получаю, это "Вызов возможно неопределенного метода doSomething через ссылку со статическим типом parentClass". и «Неявное приведение значения типа derviedClassA к несвязанному типу parentClass»


person user368652    schedule 16.06.2010    source источник
comment
какие ошибки вы получаете? doSomething определен в parentClass или только в дочерних классах?   -  person luke    schedule 17.06.2010
comment
Ваш вопрос отличается от вашего примера. В своем вопросе вы говорите, что объявляете var o:classA и пытаетесь привести его к classB, что не сработает. Однако вы должны быть в состоянии сделать то, что говорит пример, то есть объявить var o:parentClass, а затем присвоить ему значение одного из его дочерних классов. Что вы пытаетесь сделать и какие ошибки вы получаете? Кроме того, как было сказано выше: определен ли doSomething в родительском классе? Если нет, вам нужно будет выполнить кастинг заранее (например: classA(o).doSomething();)   -  person Austin Fitzpatrick    schedule 17.06.2010
comment
И, по стандартам, вы должны использовать CapitalizedNamesForClasses. Не должно влиять на ваши результаты, но просто чтобы вы знали, что эти имена нетрадиционны.   -  person Austin Fitzpatrick    schedule 17.06.2010
comment
Спасибо за ответы. Остин, я исправил ошибку; пример правильный. doSomething() определяется в parentClass как общедоступный, а в производных классах как override public function doSomething() Ошибки, которые я получаю, - это вызов возможно неопределенного метода doSomething через ссылку со статическим типом parentClass. и Неявное приведение значения типа derviedClassA к несвязанному типу parentClass.   -  person user368652    schedule 17.06.2010
comment
Такого быть не должно — вы уверены, что DerviedClassA extends ParentClass и не забыли объявить doSomething в ParentClass?   -  person Amarghosh    schedule 17.06.2010
comment
Две ошибки, которые вы получаете, предполагают, что есть нечто большее, чем просто отсутствующие расширения, которые объясняют несвязанную ошибку типа, но не тот факт, что вы даже не можете вызвать родительский класс doSomething. Мне кажется, что ваш путь к классу настроен неправильно, так что определение вашего parentClass не найдено во время компиляции. Файлы названы в соответствии с классами?   -  person Adam Smith    schedule 29.03.2011


Ответы (3)


Я делал это раньше: вызывал ошибку в том, что должно быть виртуальной функцией в базовом классе, чтобы явно указать на ее ошибочный вызов. Я делаю это, когда создаю абстрактные базовые классы.

Main.as (класс документа)

package
{
    import flash.display.Sprite;

    public class Main extends Sprite
    {
        private var superClassRef:SuperClass;
        private var idLikeToBuyAnA:Boolean = true;

        public function Main()
        {
            trace("Main()");
            if (idLikeToBuyAnA)
            {
                superClassRef = new DerivedClassA();
            }
            else
            {
                superClassRef = new DerivedClassB();
            }

            superClassRef.doSomething();
        }
    }
}

Суперкласс.as

package
{
    public class SuperClass
    {
        public function SuperClass()
        {
        }

        public function doSomething():void
        {
            throw new Error("Override me, I wish I were virtual!");
        }
    }
}

Производный классA.as

package
{
    public class DerivedClassA extends SuperClass
    {
        public function DerivedClassA()
        {
        }

        override public function doSomething():void
        {
            trace("I'm and A!");
        }
    }
}

Производный классB.as

package
{
    public class DerivedClassB extends SuperClass
    {
        public function DerivedClassB()
        {
        }

        override public function doSomething():void
        {
            trace("I'm a B!");
        }
    }
}
person Adam Smith    schedule 29.03.2011

Я бы сделал интерфейс, чтобы иметь возможность делать то, что вы просите. Это вам не нужно приводить переменную, и это даст вам доступ к вашей функции doSomething. Вот небольшой пример использования вашей структуры: Обратите внимание, что все классы находятся в одном корневом пакете, поэтому операторы импорта отсутствуют.

MainApp.as (это приложение по умолчанию)

package  
{
    import flash.display.Sprite;

    public class MainApp extends Sprite 
    {
        private var parentClass : IParent;
        private var doA : Boolean = false;

        public function MainApp()
        {

            if (doA)
            parentClass = new DerivedClassA();
            else
            parentClass = new DerivedClassB();

            parentClass.doSomething();
        }
    }
}

Родитель.как

package  
{
    import flash.display.Sprite;

    public class Parent extends Sprite
    {
        public function Parent()
        {
        }
    }
}

Производный классA.as

package  
{
    public class DerivedClassA extends Parent implements IParent
    {
        public function DerivedClassA()
        {
            super();
        }

        public function doSomething() : void 
        {
            trace (this + " done something");
        }
    }
}

Производный классB.as

package  
{
    public class DerivedClassB extends Parent implements IParent
    {
        public function DerivedClassB()
        {
            super();
        }

        public function doSomething() : void 
        {
            trace (this + " done something");
        }
    }
}

IParent.as

package  
{
    public interface IParent 
    {
        function doSomething():void;
    }
}

Как видите, используя интерфейс, вы вызываете функцию doSomething без приведения типов. Нет никаких проблем с приведением переменных, но это может дать вам более структурированный код и гарантирует наличие метода doSomething в классах, реализующих интерфейс. Надеюсь, это поможет... Удачи

person a--m    schedule 17.06.2010
comment
Я бы не рекомендовал это решение как есть. Все, что введено в качестве интерфейса, не сможет получить доступ к другим свойствам родительского класса. - person Dusty J; 29.03.2011

Конкретный ответ на заданный вами вопрос таков:

o["doSomething"]();

Однако я не могу рекомендовать вам это делать. Я думаю, что реальная проблема заключается в том, что ваш родительский класс должен определять doSomething(), тогда производные классы должны переопределять функцию.

person Dusty J    schedule 29.03.2011