Как создать массив объектов абстрактного класса в MATLAB?

В качестве примера предположим, что я создал абстрактный класс под названием Shape и два подкласса под названием Circle и Rectangle, которые реализуют (абстрактный) метод под названием Draw. Я хотел бы иметь возможность создавать несколько объектов Circle и Rectangle, хранить их в массиве и вызывать Draw для каждого объекта массива путем итерации через массив.

Я пробовал что-то вроде следующего:

Shape.m:

classdef (Abstract) Shape < handle

    methods (Abstract)
        Draw(obj);
    end

end

Circle.m:

classdef Circle < Shape

    methods
        function obj = Draw(obj)
            disp('This is a circle');
        end
    end

end

Rectangle.m:

classdef Rectangle < Shape

    methods
        function obj = Draw(obj)
            disp('This is a rectangle');
        end
    end

end

test.m:

shapes = Shape.empty();

myrect = Rectangle();
mycirc = Circle();

shapes(end + 1) = myrect;
shapes(end + 1) = mycirc;

for i = 1:size(shapes,1)
    shapes(i).Draw();
end

Когда я пытаюсь запустить test.m, я получаю следующее сообщение об ошибке:

Error using Shape.empty
Abstract classes cannot be instantiated.
Class 'Shape' defines abstract methods
and/or properties.

Error in test (line 1)
shapes = Shape.empty();

Ответы

Ответ 1

Как видно из ошибки, вы не можете создать абстрактный класс (подробнее см. ответ sebastian). Однако есть специальный суперкласс, называемый matlab.mixin.Heterogeneous, из которого вы можете получить возможность создания массива разных классов.

Сначала выведите matlab.mixin.Heterogeneous в Shape.m:

classdef (Abstract) Shape < handle & matlab.mixin.Heterogeneous

Затем в вашем тесте script инициализируйте shapes либо из Circle, либо Rectangle:

shapes = Circle.empty();

Когда вы запустите цикл, массив изменит класс:

>> shapes

shapes = 

  1x2 heterogeneous Shape (Rectangle, Circle) array with no properties.

>> shapes(1)

ans = 

  Rectangle with no properties.

>> shapes(2)

ans = 

  Circle with no properties.

Это должно быть все, что вам нужно, но для дополнительного контроля над гетерогенным массивом вы можете переопределить метод getDefaultScalarElement matlab.mixin.Heterogeneous, чтобы указать объект по умолчанию. Это должно быть переопределено для абстрактных базовых классов:

Переопределить этот метод, если Root Class является абстрактным или не является подходящим объектом по умолчанию для классов в гетерогенной иерархии. getDefaultScalarElement должен возвращать экземпляр другого члена гетерогенной иерархии.

Предположим, что объект по умолчанию должен быть Circle для массива объектов, происходящих из Shape:

methods (Static, Sealed, Access = protected)
    function default_object = getDefaultScalarElement
        default_object = Circle;
    end
end

Теперь отсутствующие элементы в массиве объектов, полученных из Shape, будут заполнены объектами Circle:

>> clear r
>> r(2) = Rectangle
r = 
  1x2 heterogeneous Shape (Circle, Rectangle) array with no properties.
>> r(1)
ans = 
  Circle with no properties.
>> r(2)
ans = 
  Rectangle with no properties.

Ответ 2

Из документов:

abstract class — A class that cannot be instantiated, but that defines class components used by subclasses.

Смотрите: Mathworks-Docs

Что такое, afaik, определение абстрактных классов на других языках программирования (кто-то поправьте меня, если я ошибаюсь).

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

EDIT: Для полноты:

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

>> objects(1) = Foo();
>> objects(2) = FooBar();
The following error occurred converting from FooBar to Foo:
Error using Foo
Too many input arguments.

>> FooBar

ans = 

  FooBar handle with no properties.
  Methods, Events, Superclasses


Superclasses for class FooBar:

    Foo
    handle

ИЗМЕНИТЬ 2: См. Решение chappjc для этой проблемы;)