Полиморфизм Matlab

ReSharper является инструментом Visual Studio, не инструментом языка. Самый близкий эквивалент был бы ИДЕЯ IntelliJ от людей, которые создали ReSharper.

9
задан chappjc 20 October 2013 в 00:49
поделиться

1 ответ

К сожалению, все элементы массива в MATLAB должны быть одного типа. Когда вы объединяете разные классы, MATLAB попытается преобразовать их все в один и тот же класс.

Если вы определили один из ваших классов как подчиненный или превосходящий другой (с помощью атрибута InferiorClasses или функции INFERIORTO / SUPERIORTO ), затем вызываются методы более высокого класса. Если вы не указали отношения между классами, тогда два объекта имеют равный приоритет, и MATLAB вызывает метод самого левого объекта. Вероятно, поэтому arr = [bc]; создает массив класса B, а arr = [cb]; создает массив класса C.

Вариант 1: Массивы ячеек

Если вы хотите выполнить метод foo , определенный для класса B на объекте b , а также выполнить метод foo , определенный для класса C на объект c , то вам, вероятно, придется использовать массивы ячеек и функцию CELLFUN . Если foo не возвращает значение, вы можете сделать что-то вроде этого:

arr = {b,c};
cellfun(@foo,arr);  % Invoke foo on each element of the cell array

Вариант 2: Развлечение с полиморфным поведением присяжных

Ради интереса я придумал возможное решение, которое технически работает, но имеет некоторые ограничения. Чтобы проиллюстрировать идею, я собрал несколько примеров классов, подобных тем, которые вы указали в вопросе. Вот абстрактный суперкласс classA :

classdef classA < hgsetget
  properties
    stuff
  end
  properties (Access = protected)
    originalClass
  end
  methods
    function foo(this)
      disp('I am type A!');
      if ~strcmp(class(this),this.originalClass)
        this = feval(this.originalClass,this);
      end
      this.fooWorker;
    end
  end
  methods (Abstract, Access = protected)
    fooWorker(this);
  end
end

И вот ' s пример подкласса classB ( classC точно такой же, где везде B заменено на C и наоборот):

classdef classB < classA
  methods
    function this = classB(obj)
      switch class(obj)
        case 'classB'  % An object of classB was passed in
          this = obj;
        case 'classC'  % Convert input from classC to classB
          this.stuff = obj.stuff;
          this.originalClass = obj.originalClass;
        otherwise      % Create a new object
          this.stuff = obj;
          this.originalClass = 'classB';
      end
    end
  end
  methods (Access = protected)
    function fooWorker(this)
      disp('...and type B!');
    end
  end
end

Конструкторы для classB и classC разработаны таким образом, что два класса могут быть преобразованы друг в друга. Свойство originalClass инициализируется при создании и указывает, каким был исходный класс объекта. Это свойство останется неизменным, если объект преобразован из одного класса в другой.

В методе foo текущий класс переданного объекта проверяется на соответствие его исходному классу. Если они отличаются, объект сначала преобразуется обратно в исходный класс перед вызовом метода fooWorker . Вот тест:

>> b = classB('hello');  % Create an instance of classB
>> c = classC([1 2 3]);  % Create an instance of classC
>> b.foo  % Invoke foo on b
I am type A!
...and type B!
>> c.foo  % Invoke foo on c
I am type A!
...and type C!
>> arr = [b c]  % Concatenate b and c, converting both to classB

arr = 

  1x2 classB handle

  Properties:
    stuff

  Methods, Events, Superclasses

>> arr(1).foo  % Invoke foo on element 1 (formerly b)
I am type A!
...and type B!
>> arr(2).foo  % Invoke foo on element 2 (formerly c)
I am type A!
...and type C!

Одно из ключевых ограничений (помимо того, что оно немного некрасиво) - это случай, когда classB и classC каждый имеет свойства, которых нет у другого. В таком случае преобразование в другой класс и последующее преобразование обратно, скорее всего, приведет к потере этих свойств (т.е. сбросу до значений по умолчанию). Однако, если бы один класс был подклассом другого, так что у него были бы все те же свойства и они, есть решение. Вы можете установить подкласс выше суперкласса (см. Обсуждение выше), чтобы конкатенация объектов двух классов всегда приводила к преобразованию объектов суперкласса в подкласс. При обратном преобразовании в "полиморфные" методы (например, foo выше) данные объекта не будут потеряны.

Я не делаю этого. Я не знаю, насколько это работоспособное решение, но, возможно, оно даст вам хотя бы несколько интересных идей. ;)

5
ответ дан 4 December 2019 в 09:37
поделиться