Я пишу несколько связанных классов C ++, и у меня возникают проблемы с дизайном конкретной унаследованной функции.
В частности, все классы являются «операциями» на деревьях, и мне нужно иметь возможность выполнять набор произвольных операций с деревьями на дереве. У меня есть функция с именем ExecuteOperation () в каждом классе.
Проблема в том, что в некоторых классах мне нужно больше дополнительной информации, чем в других. Прямо сейчас я просто передаю дополнительную информацию всем классам, с абстрактным базовым классом, определенным так:
class BasicOperation {
public:
//...
virtual void ExecuteOperation(Tree* tree, multimap<int,Foo*> extra1, multimap<int,Foo*> extra2) = 0;
//...
}
Потомкам подкласса BasicOperation, "SpecialOperation", нужны параметры extra1 и extra2, тогда как потомки "NonspecialOperation" вообще не используют эти параметры.
Вызывающий объект ExecuteOperation обычно выглядит примерно так:
Tree* tree;
std::vector<BasicOperation*> operations;
//...
for(size_t i=0;i<operations.size();i++) {
operations[i]->ExecuteOperation(tree,extra1,extra2);
}
Заполнение extra1 и extra2 зависит от конкретного дерева и может потребовать значительных вычислительных ресурсов (лучше не создавать их заново при каждом вызове ExecuteOperation).
Есть ли лучший способ спроектировать это так, чтобы только объекты SpecialOperation получали переданные им параметры? Или это просто нормально, когда неиспользуемые параметры передаются в классы, такие как NonspecialOperation?
Странно определять NonspecialOperation :: ExecuteOperation () с двумя параметрами, которые он не использует.
Единственное, о чем я до сих пор думал, - это чтобы каждый объект SpecialOperation возвращал указатель на вызывающего и сохранял дополнительную информацию в объекте вызывающего. Мне не очень нравится это решение, потому что extra1 и extra2 слишком зависят от текущего состояния; Если не считать проблем с распараллеливанием, то эта установка просто «чувствует себя неправильно».
Кроме того, обтекание дерева, extra1 и extra2 в другой структуре для передачи в ExecuteOperation может сделать его более понятным и имеет смысл, поскольку extra1 и extra2 являются дополнительными дескрипторами для дерева, но я не знаю, является ли это лучшим решением :
struct TreeEx {
Tree* tree;
multimap<int,Foo*> extra1, extra2;
};
//in BasicOperation:
virtual void ExecuteOperation(TreeEx* tree_with_info) = 0;