у меня есть следующий абстрактный базовый класс:Наследование класса с "неуместных" методы
class DLAContainer {
public:
DLAContainer() { std::random_device rd; mt_eng = std::mt19937(rd()); }
virtual void generate(std::size_t _n) = 0;
protected:
std::mt19937 mt_eng;
virtual void spawn_particle(int& _x, int& _y,
std::uniform_real_distribution<>& _dist) = 0;
virtual void spawn_particle(int& _x, int& _y, int& _z,
std::uniform_real_distribution<>& _dist) = 0;
// ... among other methods to be overridden...
};
и два класса, которые наследуют от DLAContainer
:
class DLA_2d : public DLAContainer {
public:
DLA_2d() : DLAContainer() { // initialise stuff }
void generate(std::size_t _n) { // do stuff }
private:;
std::queue<std::pair<int,int>> batch_queue;
// ...
void spawn_particle(int& _x, int& _y,
std::uniform_real_distribution<>& _dist) { // do stuff }
void spawn_particle(int& _x, int& _y, int& _z,
std::uniform_real_distribution<>& _dist) { // do nothing }
//...
};
и
class DLA_3d : public DLAContainer {
public:
DLA_3d() : DLAContainer() { // initialise stuff }
void generate(std::size_t _n) { // do stuff }
private:;
std::queue<std::tuple<int,int,int>> batch_queue;
// ...
void spawn_particle(int& _x, int& _y,
std::uniform_real_distribution<>& _dist) { // do nothing }
void spawn_particle(int& _x, int& _y, int& _z,
std::uniform_real_distribution<>& _dist) { // do stuff }
//...
};
Как вы можете видеть, есть две перегрузки spawn_particle
- одна для двумерной решетки, а другая для 3D, однако оба являются чистыми virtual
функциями и поэтому должны быть переопределены/реализованы как в подклассах DLA_2d
, так и в DLA_3d
, где 3D-метод ничего не сделает в DLA_2d
и наоборот для DLA_3d
.
Конечно, это работает, и все работает нормально, но я не могу не чувствовать, что дизайн немного неуклюжий, когда приходится применять нерелевантные методы в каждом классе.
Есть ли лучший шаблон проектирования для этого, такой как реализация отдельных интерфейсов (т. Е. ISpawnParticle_2d
и ISpawnParticle_3d
) для двух производных классов? Или в таком сценарии предпочтение отдается композиции, а не наследованию?
Редактировать: Я должен добавить, что DLAContainer
имеет несколько других методов (и полей). Некоторые из этих методов определены (чтобы они могли использоваться как DLA_2d
, так и DLA_3d
), а другие являются чисто виртуальными, аналогичными spawn_particle
. Вот почему у меня есть DLAContainer
как абстрактный базовый класс в этом случае.
Если в «DLAContainer» нет ничего, я вижу мало необходимости сделать его классом abtract. Просто имейте в хранилище генератор случайных чисел, подкласс он, реализует соответствующий 'spawn_article()' в каждом подклассе и называет его днем. Если вам действительно нужен класс abtract, бросание исключения лучше, чем ничего не делать, в не реализованной функции. Альтернативой является определение реализаций по умолчанию виртуальных функций в базовом классе (следовательно, это уже не абстрактный класс), путем исключения исключения. –
Я пропустил справедливую сумму фактического кода от 'DLAContainer' - там больше, и в идеале это должен быть абстрактный класс. Интересная идея с исключением определения бросания в базовом классе, которая может быть приятнее - плюс «DLAContainer», по-прежнему будет абстрактной в этом случае, поскольку «generate (std :: size_t)» останется чистым-виртуальным, поскольку подпись эквивалентна для «DLA_2d» 'и' DLA_3d'. – ArchbishopOfBanterbury
Вам нужно знать тип объекта перед вызовом любой из ваших функций 'spawn_particle()', поэтому нет никакой пользы от их присутствия в базовом классе вообще. Вы также можете быть объявлены каждый в своем соответствующем подклассе. – Galik