Полиморфизм дизайна, шаблон как абстрактный класс

Как вы проектируете полиморфизм, когда у вас есть член, тип которого зависит от некоторых ограничений.

Скажи, что у меня есть это:

template<typename T>
class Base
{
public:
Base() = default;
virtual ~Base() = default;
T member;
};

class DerivedA : public Base<int>
{
public:
DerivedA() {member = 5;}
};

class DerivedB : public Base<float>
{
public:
DerivedB() = default;
};

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

Base *b;
if (something)
b = new DerivedA();
else
b = new DerivedB();

Очевидно, я не могу этого сделать, так как мне нужно предоставить параметры шаблона для объявления b,

Это плохой дизайн? Как вы справляетесь с этим?

Я мог бы написать небольшую обертку:

class Wrapper() {};

template<typename T>
class Base : public Wrapper
{
// ...
};

Wrapper a, b;
a = new DerivedA;
b = new DerivedB;

Но тогда у меня не будет доступа напрямую к member или другие методы, объявленные в Base или же Derived, Я должен был бы бросить: reinterpret_cast<DerivedA*>(a)->member, делающий полиморфизм бесполезным.

Спасибо

2

Решение

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

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

Если это все еще не вариант, рассмотрите способы извлечения вашего члена. Может быть, виртуальные геттеры и сеттеры с соответствующими преобразованиями.

В крайнем случае рассмотрим boost :: option, boost :: any. Но на самом деле они реализованы с использованием техники, аналогичной вашей обертке. Таким образом, вы получаете обертку для обертки.

0

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

Хорошо, если «доступ» зависит от параметра шаблона T (такое чтение Base.member), то вы должны поставить его как-то. Приведение к одному из производных классов — это один из способов сделать это, но вам не нужно reinterpret_cast, Вы должны начать использовать указатели / ссылки, чтобы избежать обрезания и позволить взаимозаменяемость работать правильно:

Wrapper *a, *b;
a = new DerivedA;
b = new DerivedB;

int a_member = static_cast<DerivedA*>(a)->member;
float b_member = static_cast<DerivedB*>(b)->member;

И если вы добавите виртуальный метод Wrapper чтобы сделать его полиморфным, вы также можете выполнить динамическое приведение:

DerivedB* b_derived = dynamic_cast<DerivedB*>(b);
if (b_derived != nullptr) {
float b_member = b_derived->member;
// ...
}
0

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