Поддержка класса функций создания массивов

Расширение функций создания массивов для класса

Существует несколько функций MATLAB®, которые создают массивы определенного размера и типа, такие как ones и zeros. Пользовательские классы могут добавить поддержку функций создания массивов, не требуя использования синтаксиса перегруженного метода.

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

cls = class(x);
zArray = zeros(m,n,cls);

Функции создания массивов создают массивы определенного типа двумя способами:

  • Синтаксис имени класса — Задает имя класса, которое определяет тип элементов массива.

  • Синтаксис объекта прототипа — Обеспечивает объект прототипа что функциональное использование, чтобы определить тип и другие характеристики элементов массива.

Например:

zArray = zeros(2,3,'uint8');
p = uint8([1 3 5 ; 2 4 6]);
zArray = zeros(2,3,'like',p);

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

zArray = zeros(2,3,'MyClass');

Или передайте объект своего класса:

p = MyClass(...);
zArray = zeros(size(p),'like',p);

MATLAB использует эти аргументы, чтобы отправить соответствующему методу в вашем классе.

Функции создания массивов та перегрузка поддержки

Следующие функции поддерживают этот вид перегрузки.

Функции создания массивов
ones
zeros
eye
nan (нижний регистр)
inf
true
false
cast
rand
randn
randi

Какой синтаксис использовать

Чтобы создать массив объектов по умолчанию, которые не требуют никаких входных параметров для конструктора, затем используют синтаксис имени класса.

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

Классы могут поддержать и имя класса и синтаксис объекта прототипа.

Можно реализовать синтаксис имени класса с true и функциями false даже при том, что эти функции не поддерживают тот синтаксис по умолчанию.

Метод имени класса под названием то, если прототипный метод не существует

Если ваш класс реализует синтаксис имени класса, но не реализует синтаксис объекта прототипа для конкретной функции, можно все еще вызвать оба синтаксиса. Например, если вы реализуете статический метод zeros только, можно вызвать:

zeros(...,'like',MyClass(...))

В случае, в котором вы вызываете синтаксис объекта прототипа, MATLAB сначала ищет метод под названием zerosLike. Если MATLAB не может найти этот метод, он призывает к статическому методу zeros.

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

Реализация поддержки функций создания массивов

Используйте два отдельных метода поддерживать функцию создания массивов. Один метод реализует синтаксис имени класса и другие реализации синтаксис объекта прототипа.

Например, чтобы поддерживать функцию zeros:

  • Реализуйте синтаксис имени класса:

    zeros(...,'ClassName')

    Как метод Static:

    methods (Static)
       function z = zeros(varargin)
          ...
       end
    end
  • Реализуйте синтаксис объекта прототипа:

    zeros(...,'like',obj)

    Как метод Hidden с вектором char 'Like', добавленный к имени.

    methods (Hidden)
       function z = zerosLike(obj,varargin)
          ...
       end
    end

Как MATLAB интерпретирует вызов функции

Специальная поддержка функций создания массивов следует из интерпретации синтаксиса.

  • Вызов функции zeros этой формы:

    zeros(...,'ClassName')
    

    Вызывает статический метод класса с этим синтаксисом:

    ClassName.zeros(varargin{1:end-1})
  • Вызов функции zeros этой формы:

    zeros(...,'like',obj)

    Вызывает метод класса с этим синтаксисом:

    zerosLike(obj,varargin{1:end-2})

Поддержка всех входных параметров функции

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

  • Никакие входные параметры размерности, приводящие к возврату скаляра. Например:

    z = zeros('MyClass');
  • Одно или несколько измерений равняется или меньше, чем нуль, приводящий к пустому массиву. Например:

    z = zeros(2,0,'MyClass');
  • Любое количество допустимых измерений массива, задающих размер массива. Например:

    z = zeros(2,3,5,'MyClass');

Когда вызовы функции создания массивов ваш метод класса, это передает входные параметры, исключая имя класса или литеральный 'like' и переменную объекта к вашему методу. Можно реализовать методы с этими подписями:

  • zeros(varargin) для методов “имени класса”

  • zeros(obj,varargin) для “как объект прототипа” методы

Демонстрационный класс

Класс Color представляет цвет в определенном цветовом пространстве, такой как, RGB, HSV, и так далее. Обсуждения в Реализациях метода Имени класса и Реализации метода Объекта прототипа используют этот класс в качестве основания для реализаций перегруженного метода.

classdef Color
   properties
      ColorValues = [0,0,0]
      ColorSpace = 'RGB'
   end
   methods
      function obj = Color(cSpace,values)
         if nargin > 0
            obj.ColorSpace = cSpace;
            obj.ColorValues = values;
         end
      end
   end
end

Реализации метода имени класса

Функция zeros разделяет итоговый ClassName вектор char и использует его, чтобы сформировать вызов статического метода в классе Color. Аргументы, переданные статическому методу, являются аргументами измерения массива.

Вот реализация метода zeros для класса Color. Эта реализация:

  • Задает метод zeros как (требуемый) Static

  • Возвращает скалярный объект Color, если вызов zeros не имеет никаких аргументов размерности

  • Возвращает пустой массив, если вызов zeros имеет какие-либо аргументы размерностей, равные 0.

  • Возвращает массив объектов Color по умолчанию. Используйте repmat, чтобы создать массив размерностей, заданных вызовом zeros.

classdef Color
   ...
   methods (Static)
      function z = zeros(varargin)
         if (nargin == 0)
         % For zeros('Color')
            z = Color;
         elseif any([varargin{:}] <= 0)
         % For zeros with any dimension <= 0   
            z = Color.empty(varargin{:});
         else
         % For zeros(m,n,...,'Color')
         % Use property default values
            z = repmat(Color,varargin{:});
         end
      end
   end
end

Метод zeros использует значения по умолчанию для свойства ColorValues, потому что эти значения подходят для этого приложения. Реализация метода ones может установить свойство ColorValues на [1,1,1], например.

Предположим, что вы хотите перегрузить функцию randi, чтобы достигнуть следующих целей:

  • Задайте каждое свойство ColorValue как 1 3 массив в области значений 1 к заданному максимальному значению (например, 1–255).

  • Разместите скаляр, пустые размеры, и многомерного массива.

  • Возвратите массив объектов Color заданных измерений, каждого со случайным ColorValues.

classdef Color
   ...
   methods (Static)
      function r = randi(varargin)
         if (nargin == 0)
            % For randi('ClassName')
            r = Color('RGB',randi(255,[1,3]));
         elseif any([varargin{2:end}] <= 0)
            % For randi with any dimension <= 0
            r = Color.empty(varargin{2:end});
         else
            % For randi(max,m,n,...,'ClassName')
            if numel([varargin{:}]) < 2
               error('Not enough input arguments')
            end
            dims = [varargin{2:end}];
            r = zeros(dims,'Color');
            for k = 1:prod(dims)
               r(k) = Color('RGB',randi(varargin{1},[1,3]));
            end
         end
      end
   end
end

Реализация метода объекта прототипа

Цель метода, который возвращает массив объектов, которые “похожи на объект прототипа”, зависит от требований класса. Для класса Color метод zeroLike создает объекты, которые имеют значение свойства ColorSpace объекта прототипа, но ColorValues является всем нулем.

Вот реализация метода zerosLike для класса Color. Эта реализация:

  • Задает метод zerosLike как Hidden

  • Возвращает скалярный объект Color, если вызов функции zeros не имеет никаких аргументов размерности

  • Возвращает пустой массив, если вызов функции zeros имеет какие-либо аргументы размерности, которые отрицательны или равны 0.

  • Возвращает массив объектов Color размерностей, заданных вызовом функции zeros.

classdef Color
   ...
   methods (Hidden)
      function z = zerosLike(obj,varargin)
         if nargin == 1
            % For zeros('like',obj)
            cSpace = obj.ColorSpace;
            z = Color;
            z.ColorSpace = cSpace;
         elseif  any([varargin{:}] <= 0)
            % For zeros with any dimension <= 0
            z = Color.empty(varargin{:});
         else
            % For zeros(m,n,...,'like',obj)
            if ~isscalar(obj)
               error('Prototype object must be scalar')
            end
            obj = Color(obj.ColorSpace,zeros(1,3,'like',obj.ColorValues));
            z = repmat(obj,varargin{:});
         end
      end
   end
end

Полный список классов

Вот определение класса Color с перегруженными методами.

Примечание

В фактической практике класс Color требует проверки ошибок, преобразований цветового пространства, и так далее. Эта чрезмерно упрощенная версия иллюстрирует реализацию перегруженных методов.

classdef Color
   properties
      ColorValues = [0,0,0]
      ColorSpace = 'RGB'
   end
   methods
      function obj = Color(cSpace,values)
         if nargin > 0
            obj.ColorSpace = cSpace;
            obj.ColorValues = values;
         end
      end
   end
   methods (Static)
      function z = zeros(varargin)
         if (nargin == 0)
            % For zeros('ClassName')
            z = Color;
         elseif any([varargin{:}] <= 0)
            % For zeros with any dimension <= 0
            z = Color.empty(varargin{:});
         else
            % For zeros(m,n,...,'ClassName')
            % Use property default values
            z = repmat(Color,varargin{:});
         end
      end
      function r = randi(varargin)
         if (nargin == 0)
            % For randi('ClassName')
            r = Color('RGB',randi(255,[1,3]));
         elseif any([varargin{2:end}] <= 0)
            % For randi with any dimension <= 0
            r = Color.empty(varargin{2:end});
         else
            % For randi(max,m,n,...,'ClassName')
            if numel([varargin{:}]) < 2
               error('Not enough input arguments')
            end
            dims = [varargin{2:end}];
            r = zeros(dims,'Color');
            for k = 1:prod(dims)
               r(k) = Color('RGB',randi(varargin{1},[1,3]));
            end
         end
      end
   end
   methods (Hidden)
      function z = zerosLike(obj,varargin)
         if nargin == 1
            % For zeros('like',obj)
            cSpace = obj.ColorSpace;
            z = Color;
            z.ColorSpace = cSpace;
         elseif  any([varargin{:}] <= 0)
            % For zeros with any dimension <= 0
            z = Color.empty(varargin{:});
         else
            % For zeros(m,n,...,'like',obj)
            if ~isscalar(obj)
               error('Prototype object must be scalar')
            end
            obj = Color(obj.ColorSpace,zeros(1,3,'like',obj.ColorValues));
            z = repmat(obj,varargin{:});
         end
      end
   end
end

Похожие темы