шаблоны — Руководство по созданию дизайна для составных классов с множественным наследованием в Stack Overflow

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

Решение дизайна, включающего множественное наследование и составные классы в C ++

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

Составное требование:

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

Требование множественного наследования:

Типы входных данных, которые я использую для каждого из этих классов, не постоянны. Иногда у меня есть данные типа 1, а иногда — данные типа 2. Различные типы данных, которые у меня есть для любого данного проекта, могут меняться со временем. Чтобы не иметь чудовищно растущего класса галактик, который получает новые переменные и функции-члены для каждого типа данных, не доступных для каждого проекта, а также для всех старых (и, возможно, неиспользуемых в текущем проекте), я хочу разбить галактику solarSystem Классы планеты и Луны объединяются в связанные классы, каждый из которых специализируется на работе с определенным набором данных.

Таким образом, если я рассматриваю два из доступных мне наборов данных data1 и data2, я могу выбрать создание конкретных версий каждого класса для каждого набора данных.

Мне нравится этот подход, потому что, если у меня есть новый проект, который требует комбинации data1 и data2, я могу создать новые классы для классов galaxy, solarySystem, planet и moon, которые наследуются от обоих соответствующих типов ранее. Что-то вроде следующего.

class GalaxyOneTwo: public GalaxyOne, public GalaxyTwo { /* . . .  */ };
class SolarSystemOneTwo: public SolarSystemTwo, public SolarSystemOne{ /* . . . */};
class PlanetOneTwo: public PlanetTwo, public PlanetOne{ /* . . . */ };
class MoonOneTwo: public MoonTwo, public MoonOne{ /* . . . .*/};

Это дает мне доступ ко всем проверяемым объектам и методам для работы с данными1 и данными2, и я могу дополнительно определить переменные и методы для работы с новыми свойствами, возникающими из комбинации данных1 и данных2.

Эта проблема:

Каждая из этих идей дизайна, составное требование и требование множественного наследования работали для меня сами по себе. Но я бы очень хотел использовать оба. Сложность использования обоих заключается в том, что те контейнерные переменные в GalaxyOne, которые предоставляют ему доступ к указателям SolarSystemOne, бесполезны для GalaxyOneTwo, поскольку типы указателей в SolarSystemOne не предоставляют доступ к функциям-членам SolarSystemOneTwo.

Возможные решения:

Шаблон Базовый класс-
Создайте базовый класс шаблона PrimitiveGalaxy, PrimitiveSolarSystem, PrimitivePlanet, PrimitiveMoon, который содержит все переменные контейнера и соответствующие методы получения и установки, от которых наследуются все остальные классы. Это подход, который я использовал в ссылке, размещенной выше, и его проблемы можно найти там.

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

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

Пока что вышеупомянутое возможное решение — единственное, которое я в настоящее время понимаю достаточно хорошо, чтобы опубликовать.

Мне нужно решение, которое учитывает гибкий код, который не требует сложного синтаксиса и не требует каждой растущей и неуправляемой серии очень больших определений классов. Мои проекты регулярно включают новые виды данных, поэтому я хочу иметь возможность легко создавать новые парсеры для этих новых данных и легко включать данные в мои различные проекты с использованием классов Galaxy, SolarSystem, Planet и Moon.

0

Решение

Я смог решить свою проблему с помощью абстрактного базового класса. Абстрактный базовый класс содержит все мои переменные контейнера и соответствующие переменные getter и setter. Кроме того, абстрактный базовый класс определяет абстрактные методы для всех методов, которые будут использоваться в любом производном классе. Эти методы окружены директивами препроцессора, которые включают эти виртуальные функции только в том случае, если включен соответствующий заголовочный файл, который определяет указанные функции, что предотвращает дальнейшие абстрактные классы.

class Galaxy{
protected:
std::vector<SolarSystem*> solarSystems;
public:
void addSolarSystem(SolarSystem*);
#ifdef GALAXYONE
virtual void aGalaxyOneMethod()=0;
#endif

#ifdef GALAXYTWO
virtual void aGalaxyTwoMethod()=0;
#endif

#ifdef GALAXYONETWO
virtual void aGalaxyOneTwoMethod()=0;
#endif

enter code here

};

GalaxyOne.h

#define GALAXYONE
class GalaxyOne{
protected:
/*Private Variables for GalaxyOne*/
public:
void aGalaxyOneMethod(); //No longer abstract
};

GalaxyTwo.h

#define GALAXYTWO
class GalaxyTWO{
protected:
/*Private Variables for GalaxyTwo*/
public:
void aGalaxyTwoMethod(); //No longer abstract
};

GalaxyOneTwo.h

#define GALAXYONE
#define GALAXYTWO
#define GALAXYONETWO
class GalaxyOneTwo: virtual public GalaxyOne, virtual public GalaxyTwo{
protected:
/*Private Variables for GalaxyOneTwo*/
public:
void aGalaxyOneTwoMethod(); //No longer abstract
};

Эта схема позволяет создать объект типа GalaxyOneTwo, сохранить его в указателе Galaxy и при этом иметь доступ к соответствующим функциям. Аналогичная стратегия используется с SolarSystems, Planets and Moons

1

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

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

По вопросам рекламы [email protected]