C ++ эквивалент Matlab Abstract для свойств класса

Укороченная версия:
Рассмотрим следующий псевдокод:

class Foo {
private:
abstract type myVar;
} // This class is abstract

Как бы вы реализовали это поведение в стандарте C ++?


Длинная версия:
Я должен портировать много Obj-ориентированного кода с Matlab на C ++.
Обратите внимание, что я — наименее опытный человек в мире с Matlab, и я не использую C ++ с 2007 года.

Я много гуглил по этой теме, но не смог найти правильный ответ на свой вопрос.
И вот я здесь 🙂

Допустим, у вас есть этот класс Matlab:

classdef Foo < handle
properties (Abstract, Dependent)
A
end

properties
B
end

methods (Abstract)
computeA()
end

methods (Access = protected)
function obj = Foo(bar)
obj.B = Matlab.BlaBlaBla(bar)
end
end

Этот класс (я полагаю) не может быть выделен «напрямую», так как его конструктор защищен.
Также свойство «A» является абстрактным (на мгновение игнорируем тот факт, что также является зависимым).
MathWorks говорит нам, что это означает, что:

  • Конкретные подклассы должны переопределять абстрактные свойства без
    Абстрактный атрибут, и должны использовать те же значения для SetAccess и
    Атрибуты GetAccess, используемые в абстрактном суперклассе.
  • Абстрактные свойства не могут определять методы set или get (см.
    Методы доступа к свойствам) и не может указывать начальные значения.
    подкласс, который определяет конкретное свойство, может создать множество или получить
    получить доступ к методам и указать начальные значения.

Так как бы вы правильно перевели такое поведение в C ++?
Было бы правильно, если бы я поступил следующим образом? (По праву я имею в виду, что это не плохая практика проектирования)

class Foo {
private:
type A;
type B;
protected:
virtual void computeA() = 0;
Foo(type bar) { this.B = SomeFoo(bar); }
}

Что я думаю (и могу ошибаться), так это то, что если я это сделаю, то придется

class Subclass: Foo {
protected:
void computeA(){...}
public:
type A() { computeA(); return A; } //This is A getter that grants Dependent behavior
}

Или иначе получите ошибку во время компиляции.

Я ошибся? Есть ли лучший способ сделать это?
Также это правильный способ перевести ключевое слово Dependent?

4

Решение

Прежде всего, я думаю, что важно спросить: каков общедоступный интерфейс класса (каковы его обязанности, как он взаимодействует с другими)?

Из вашего кода Matlab ответ таков: класс определяет свойства A и B, а также метод computeA. Из моего понимания зависимых свойств я сомневаюсь, что computeA () должна быть публичной (см. Matlab Docs). Если остальная часть вашего кода нуждается в этом, конечно, вы можете оставить его общедоступным, но я постараюсь уменьшить доступность.

Теперь концепция свойства не существует в C ++. Самое смешное в Matlab состоит в том, что базовый класс решает, есть ли A.get, A.set или оба, а также доступность. Я не знаю причины этого, но в моих глазах это не имеет особого смысла. В C ++ я бы перевел свойства в методы get / set. Увидеть этот вопрос для обсуждения реализации их в C ++. В зависимости от вашего выбора, вы можете реализовать независимые свойства как объекты-члены или как методы get / set.

Как только вы определили открытый интерфейс вашего метода, я постараюсь начать думать о том, как его реализовать. Обратите внимание, что управление памятью в Matlab и C ++ отличается (Matlab использует Copy on Write и заботится об управлении памятью, ничего этого не существует в чистом C ++). Кроме того, кэширование значений (как это делается с computeA и зависимыми свойствами) может потребоваться в (медленном объектно-ориентированном) коде Matlab, но не обязательно в C ++. Чтобы избежать преждевременной оптимизации, почему бы просто не сделать:

class Foo {
public:
ClassB B;
virtual ClassA getA() = 0;
//define a setA()=0 if you need it here
protected:
//I wouldn't force subclasses to have the "caching" of dependent properties, so no virtual void computeA() = 0;
Foo(ClassBar const& bar) { this.B = ClassB(bar); /*Note that SomeFoo cannot be assigned to B*/ }
}
class Subclass: public Foo {
private:
ClassA A;
public:
ClassA getA() { ClassA A; /*compute A*/ return A; }
}

Если вы чувствуете, что вычисление A слишком медленное, вы все равно можете «локально кэшировать A» в подклассе:

class Subclass: public Foo {
private:
ClassA A;
public:
ClassA getA() { /*compute A if required*/ return A; }
}

Если вы действительно хотите хранить A в Foo, я бы предпочел реализовать его как

class Foo {
private:
ClassA A;
public:
ClassB B;
ClassA getA() { if (!A.initialized) A=computeA(); return A; };
protected:
virtual ClassA computeA() = 0;
Foo(ClassBar const& bar) { this.B = ClassB(bar); /*Note that SomeFoo cannot be assigned to B*/ }
}
class Subclass: public Foo {
protected:
virtual ClassA computeA() {...}
}

И не забывайте всегда думать о том, действительно ли вы хотите передать (постоянную) ссылку или значение …

2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector