#c #inheritance
Вопрос:
void C :: setmethodForC(...)
{
B::setmethod(...);
}
class C: public A, public B
{
public:
void setmethodForC();
.....
}
В приведенном выше коде A и B-это две службы, которые использует класс C. Теперь этот код действителен для нескольких целей, и все цели не поддерживают службу B. Поэтому мне понадобилось условное наследование, где служба B включена только для определенных целей. Для этого я внес следующие изменения, чтобы отключить использование службы B в C.
#ifdef B_SUPPORTED
void C :: setmethodForC(...)
{
B::setmethod(...);
}
#endif
class C: public A
#ifdef B_SUPPORTED
, public B
#endif
{
public:
#ifdef B_SUPPORTED
void setmethodForC();
.....
#endif
}
Поскольку это хорошо скомпилировано, но есть ли лучший способ сделать это?
Комментарии:
1. Вы должны быть более конкретны в своем примере использования. Обычно я бы выбрал «предпочитаю композицию, а не наследование», но я не могу сказать, подходит ли это вам, информация слишком расплывчата
2. @Moia отредактировал вопрос для получения более подробной информации.
3. Есть ли у вас какие-либо причины добавлять новые методы вместо того, чтобы оставлять их пустыми, если отсутствует функциональность?
4. Это классический пример проблемы XY . Пожалуйста, объясните, ЗАЧЕМ вам это нужно, так как я уверен, что есть лучший и более простой способ решить вашу реальную проблему. Можно сделать то, что вы просили, но это странно в данном контексте, и это квалифицируется как продвинутое решение (я не хочу запутывать ваш разум).
Ответ №1:
В вашем вопросе неясно, почему здесь необходимо наследование, вы можете достичь желаемого результата, используя композицию и шаблон нулевого объекта https://en.wikipedia.org/wiki/Null_object_pattern, вот пример:
#include <iostream>
#include <memory>
struct OptionalService
{
virtual void someMethod() = 0;
virtual ~OptionalService() {}
};
struct DoSomethingService final : OptionalService
{
void someMethod() override { std::cout << "Do Something" << std::endl; }
};
struct NoActionService final : OptionalService
{
void someMethod() override { }
};
class MyClass
{
std::unique_ptr<OptionalService> _service;
public:
explicit MyClass(std::unique_ptr<OptionalService> service) : _service(std::move(service)) {}
void someMethod( ) { _service->someMethod(); }
};
int main() {
MyClass noAction(std::make_unique<NoActionService>());
noAction.someMethod();
MyClass someAction(std::make_unique<DoSomethingService>());
someAction.someMethod();
return 0;
}
Что-то подобное можно получить, используя статический полиморфизм ase хорошо, это избавит вас от класса интерфейса:
template<typename Service>
class MyClassB
{
Service _service;
public:
explicit MyClassB(const Serviceamp; s = Service()) : _service(s) {}
void someMethod() { _service.someMethod(); }
};
typedef MyClassB<NoActionService> MyClassBNoAction;
typedef MyClassB<DoSomethingService> MyClassBSomething;
int main() {
MyClassBNoAction noAction;
noAction.someMethod();
MyClassBSomething someAction;
someAction.someMethod();
return 0;
}
Комментарии:
1. Невозможно сказать, действительно ли это нужно ОП. В любом случае вам не нужно использовать
std::unique_ptr
здесь. Передача службы по ссылке предотвратит обнуление и не приведет к принудительному использованию кучи.2. Я согласен, вопрос расплывчатый, но я думаю, что эта техника «могла бы» быть полезной, и ее было слишком много, чтобы помещать в комментарий. Я понимаю вашу точку зрения на использование ссылки вместо unique_ptr. Но в этом случае мы будем использовать «агрегацию» вместо «композиции», и это внесет соображения о сроке службы и назначаемости класса.
Ответ №2:
Как уже было сказано, вопрос не очень ясен, и это, вероятно, проблема XY. Сказав это, один из способов справиться с различными целевыми классами-это перенести проблему с определения на создание.
Целевой конкретный класс теперь является дочерним по отношению к общему классу
фу.ч
class FooBase {};
class FooGeneric : public FooBase {};
class FooTargetSpecificA : public FooGeneric{};
class FooTargetSpecificB : public FooGeneric{};
Переместите целевой параметр в переменную времени компиляции. Однако есть и другие способы добиться этого.
цель.h
#ifdef A_SUPPORTED
constexpr bool HasFeatureA = true;
#else
constexpr bool HasFeatureA = false;
#endif
#ifdef B_SUPPORTED
constexpr bool HasFeatureB = true;
#else
constexpr bool HasFeatureB = false;
#endif
Делегируйте построение вашего объекта на фабрику с проверкой времени компиляции для правильного класса.
завод.ч
#include "foo.h"
#include "target.h"
inline std::unique_ptr<FooBase> createFoo()
{
if constexpr (HasFeatureA)
return std::make_unique<FooTargetSpecificA>();
else if constexpr (HasFeatureB)
return std::make_unique<FooTargetSpecificB>();
else
return std::make_unique<FooGenerc>();
}