在 C++ 中寻找更好的条件继承方法

Posted

技术标签:

【中文标题】在 C++ 中寻找更好的条件继承方法【英文标题】:Looking for better approach for conditional inheritance in 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 的经典例子。请解释你为什么需要这个,因为我确信有更好和更简单的方法来解决你的实际问题。可以按照您的要求进行操作,但是在这种情况下很奇怪,它可以称为高级解决方案(我不想打扰您)。 【参考方案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>();

【讨论】:

以上是关于在 C++ 中寻找更好的条件继承方法的主要内容,如果未能解决你的问题,请参考以下文章

C++认知继承

将继承重构为在 C++ 中保持多态功能的组合

C++ 中的继承:在父子类中定义变量

C++单例设计:使用继承只调用一些实现的方法

8-1:C++继承之对继承的理解和继承的基本使用,继承的格式

09 继承