C ++ дизайн: сокращение связи в глубокой иерархии классов

Пожалуйста, рассмотрите эту иерархию классов:

#include <iostream>

struct Base
{
Base(int arg1, int arg2, int arg3, int arg4)
{
std::cout << "Base::Base:" << arg1 << "," << arg2 << "," << arg3 << "," << arg4 << std::endl;
}
void BaseDoWork()
{
std::cout << "Base::BaseDoWork" << std::endl;
}
};

struct Derived1:public Base
{
Derived1(int arg1, int arg2, int arg3, int arg4):Base(arg1, arg2, arg3, arg4){}
void DerivedDoWork()
{
BaseDoWork();
}
};

struct Derived2:public Derived1
{
Derived2(int arg1, int arg2, int arg3, int arg4):Derived1(arg1, arg2, arg3, arg4){}
};

int main(int argc, char *argv[])
{
Derived2 myDerived2(1,2,3,4);
myDerived2.DerivedDoWork();
return 0;
}

Класс Derived1 имеет больше связей, чем мне бы хотелось: он должен знать, как создать «базовый» класс. В глубокой иерархии это будет означать распространение аргументов для конструктора «Базового» класса на всем протяжении иерархии классов. Изменение конструктора класса «Base» потребует изменения всех производных классов.

Мои цели для этой иерархии классов:

  1. Derived1 ожидает метод BaseDoWork () в базовом классе, но ему не нужно знать, как создать базовый класс.

  2. Derived2 знает, как создать «базовый» класс.

В идеале я хотел бы сделать Derived1 шаблоном, принимающим любой базовый класс с доступным методом «BaseDoWork ()», по следующим направлениям:

template <T> struct Derived1:public T
{
void DerivedDoWork()
{
BaseDoWork();
}
};

Но если я создаю экземпляр вышеупомянутого шаблона как Derived1<Base> Я не могу понять, как создать «базовый» класс, не добавив знания об «базовых» аргументах конструктора в Derived1.

0

Решение

Предполагая, что это реальная иерархия, если Derived1 это Base производный класс, должен знать, как создать родительский класс (Base).

Как я понял, может я и ошибаюсь, если Derived1 на самом деле не Base производный (дочерний) класс, и ему нужно только знать его интерфейс, не нужно знать, как создать Base пример. Таким образом, вы можете определить Derived1 следующим образом:

struct Derived1
{
Derived1(int arg1, int arg2, int arg3, int arg4)
{}

.....
};

Только Base производные классы должны знать, как строить Base:

struct Derived2 : public Base
{
Derived2(int arg1, int arg2, int arg3, int arg4) :
Base(arg1, arg2, arg3, arg4)
{}

.....
};

Сейчас если Derived2 действительно Derived1 ребенок, должен знать, как создать своего родителя. Предыдущий код стал:

struct Derived2 : public Base, public Derived1
{
Derived2(int arg1, int arg2, int arg3, int arg4) :
Base(arg1, arg2, arg3, arg4),
Derived1(arg1, arg2, arg3, arg4)
{}

.....
};

Если вы должны использовать Base::BaseDoWork() метод из Derived1Вы можете определить классы следующим образом:

struct Base
{
Base(int arg1, int arg2, int arg3, int arg4)
{
std::cout << "Base::Base:" << arg1 << "," << arg2 << "," << arg3 << "," << arg4 << std::endl;
}

virtual void BaseDoWork()
{
std::cout << "Base::BaseDoWork" << std::endl;
}
};

struct Derived1
{
Derived1(int arg1, int arg2, int arg3, int arg4)
{}

template <typename T>
void DerivedDoWork(T & base)  // only knows T interface
{
base.BaseDoWork();
}
};

struct Derived2 : public Base, public Derived1
{
Derived2(int arg1, int arg2, int arg3, int arg4) :
Base(arg1, arg2, arg3, arg4),
Derived1(arg1, arg2, arg3, arg4)
{}

virtual void DerivedDoWork()
{
Derived1::DerivedDoWork<Base>(*(static_cast<Base *>(this)));
}
};

Главное держит то же самое.

Возможно, вам нужно пересмотреть эту иерархию.

1

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

Когда вы делаете public наследование Derived1 от BaseВ результате получается, что Derived1 уже знает, как построить Baseтак что если хотите Derived1 не знаю, как построить Baseможет быть, лучше не наследовать его от Base? Вместо этого отдельный Base как какой-то исполнитель.

Рассмотрим этот фрагмент кода, я не утверждаю, что это решение, но, возможно, оно подтолкнет вас к другим мыслям (имена классов совпадают):

#include <iostream>

struct Base
{
Base()
{
std::cout << "Base::Base:" << std::endl;
}
Base(int arg1, int arg2, int arg3, int arg4)
{
std::cout << "Base::Base:" << arg1 << "," << arg2 << "," << arg3 << "," << arg4 << std::endl;
}
void DoWork()
{
std::cout << "Base::BaseDoWork" << std::endl;
}
};

template <typename T>
struct Derived1
{
T object;

Derived1(T obj){ object = obj; }
void DerivedDoWork()
{
object.DoWork();
}
};

template <typename T>
struct Derived2 : public Derived1<T>
{
Derived2(int arg1, int arg2, int arg3, int arg4) : Derived1( T(arg1, arg2, arg3, arg4))
{ }
};

int main(int argc, char *argv[])
{
Derived2<Base> myDerived2(1,2,3,4);
myDerived2.DerivedDoWork();
return 0;
}
1

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