Как передать полиморфный объект как производный? - PullRequest
0 голосов
/ 08 сентября 2018

для простоты у меня есть два класса: ActionTaken и MovementTaken. MovementTaken является производным классом от ActionTaken. У меня есть Queue, полный действий, и каждое действие имеет char, который определяет тип действия. (Каждое действие имеет правильный тип) Я хочу передать элементы Queue в функцию, которая работает конкретно с параметром MovementTaken, но, поскольку я использую полиморфизм, параметр имеет тип ActionTaken, но затем Я не могу использовать переменные-члены из MovementTaken, но не существует в ActionTaken. Но если я установлю параметр функции activateMovement на тип MovementTaken, я думаю, что будет ошибка, говоря, что вы не можете преобразовать базовый тип в производный тип. Вот код:

public abstract class ActionTaken : MonoBehaviour
{
    public char type;
    public Transform minionTakingAction;
}

public class MovementTaken : ActionTaken
{
    public int targetTileH;
    public int targetTileV;
    public MovementTaken(Transform _minionTakingAction, int _targetTileH, int _targetTileV)
    {
        type = 'M';
        minionTakingAction = _minionTakingAction;
        targetTileH = _targetTileH;
        targetTileV = _targetTileV;
    }
}

Queue<ActionTaken> actionTaken;
public void activateMovement(ActionTaken toActivate)
{//some code using toActivate's members targetTileH and targetTileV}

Ответы [ 2 ]

0 голосов
/ 08 сентября 2018

Преимущество Abstract классов заключается в определении базовой реализации или в принудительном использовании производных типов в деталях реализации:

public abstract class ActionTaken : MonoBehaviour
{
    public char Type { get; protected set; }
    public Transform Target { get; }

    // base ctor
    protected ActionTaken(Transform target)
    {
        Type = '\0'; 
        Target = target;
    }

    // Force implementation onto sub class
    public abstract void Activate();
}

public class MovementTaken : ActionTaken
{
    public int TileH { get; set; }
    public int TileV { get; set; }

    public MovementTaken(Transform target, int tileH, int tileV)
        : base(target)
    {
        Type = 'M';
        TileH = tileH;
        TileV = tileV;
    }

    public override void Activate()
    {
        //some code using TileH and TileV
    }
}

Поэтому ваш код вызова будет:

Queue<ActionTaken> actionTaken;
public void activateMovement(ActionTaken action)
{
    action.Activate();
}

Я также не уверен, для чего используется Type, но если вам все еще это нужно, лучше использовать константу, определенную в каждом классе, которая получается из ActionTaken, если у вас больше.

Это может иметь смысл, если в итоге вы заполните Queue<ActionTaken> различными производными типами движений. В противном случае ваш метод ActivateMovement может оказаться длинным оператором switch.

Здесь также может быть полезен интерфейс:

public interface IActionTaken
{
    Transform Target { get; }

    void Activate();
}

Что бы вы потом заменили в своей очереди: Queue<IActionTaken> Actions

Код для вызова всех действий в очереди может быть очень простым:

while(Actions.Count > 0)
{
    IActionTaken current = Actions.Dequeue();
    current.Activate();
}
0 голосов
/ 08 сентября 2018

Если вы знаете, что аргумент, переданный методу, является экземпляром MovementTaken, вы можете просто уменьшить его:

public void activateMovement(ActionTaken toActivate)
{
    MovementTaken casted = toActivate as MovementTaken;
    // Do something with casted.targetTileH and/or caster.targetTileV
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...