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

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

Существует несколько 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) для методов «like prototype object»

Класс образца

The 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

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

The 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

The zeros метод использует значения по умолчанию для ColorValues свойство, поскольку эти значения подходят для этого приложения. A реализации a 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

Похожие темы