在 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++ 中寻找更好的条件继承方法的主要内容,如果未能解决你的问题,请参考以下文章