【问题标题】:Looking for better approach for conditional inheritance in C++在 C++ 中寻找更好的条件继承方法
【发布时间】:2021-06-04 07:45:46
【问题描述】:
void C :: setmethodForC(...)
{
   B::setmethod(...);
}

class C: public A, public B
{

   public:

    void setmethodForC();
    .....

}

在上面的代码中,A 和 B 是 C 类使用的两个服务。现在此代码对多个目标有效,并且所有目标都不支持服务 B。所以我需要条件继承,其中服务 B 仅对特定目标启用。为此,我进行了以下更改以禁用在 C 中使用服务 B。

#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

}

因为编译得很好,但是有没有更好的方法来做到这一点?

【问题讨论】:

  • 您应该更具体地说明您的用例。通常我会选择“更喜欢组合而不是继承”,但我不能说这是否适合你,信息太模糊了
  • @Moia 编辑问题了解更多详情。
  • 如果功能缺失,您是否有理由添加新方法而不是留空?
  • 这是XY problem 的经典例子。请解释你为什么需要这个,因为我确信有更好和更简单的方法来解决你的实际问题。可以按照您的要求进行操作,但是在这种情况下很奇怪,它可以称为高级解决方案(我不想打扰您)。

标签: c++ inheritance


【解决方案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;
}

使用静态多态也可以很好地获得类似的东西,它将为您节省接口类:

template<typename Service>
class MyClassB
{
    Service _service;
public:
    explicit MyClassB(const Service& 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;
}

【讨论】:

  • 无法判断 OP 是否真的需要它。无论如何,您不必在这里使用std::unique_ptr。通过引用传递服务将防止 null 并且不会强制使用堆。
  • 我同意,这个问题很模糊,但我认为这种技术“可能”很有用,而且放在评论中实在是太多了。我明白你使用参考而不是 unique_ptr 的观点。但在这种情况下,我们将使用“聚合”而不是“组合”,它会考虑服务的生命周期和类的可分配性。
【解决方案2】:

正如已经说过的,这个问题不是很清楚,这可能是一个 XY 问题。也就是说,处理不同目标特定类的一种方法是将问题从定义转移到创建。

目标特定类现在是通用类的子类

foo.h

class FooBase {};

class FooGeneric : public FooBase {};

class FooTargetSpecificA : public FooGeneric{};

class FooTargetSpecificB : public FooGeneric{};

将目标选项移动到编译时间变量。不过,还有其他方法可以实现。

target.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

将对象的构造委托给工厂,并在编译时检查正确的类。

factory.h

#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>();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多