首页 > 解决方案 > 具有派生类实例的工厂

问题描述

我有一种奇怪的用例。这是它的一个非常简化的版本。

假设我有一个类Base和类DerivedOneDerivedTwo它们是从Base该类派生的。

然后,有一个枚举:

enum DerClasses {Derived1, Derived2};

和一个函数,它将接受一个枚举并返回派生类的实例,具体取决于值。

就像是:

inline Base* create_instance(DerClasses enum_class){
    switch(enum_class) {
        case Derived1:
            return new Derived1();
        case Derived2:
            return new Derived2();
    }
}

显然这是可行的,但只能在之后强制转换为派生类。

Derived1 *derived_pointer = dynamic_cast<Derived1*>(pointer);

而且我不希望用户自己制作这些动态演员表,甚至对这些类一无所知。

是否有可能以某种方式隐藏这些演员表并制作一个具有自动类型推断的 API,例如

auto ptr = create_instance(DerClasses::Derived1);
ptr->derived1_class_only_variable = 123;

标签: c++c++11inheritancedesign-patternspolymorphism

解决方案


template<DerClasses enum_class>
auto create_instance(){
  if constexpr (enum_class == DerClasses::Derived1) {
    return std::make_unique<Derived1>();
  else if constexpr (enum_class == DerClasses::Derived2) {
    return std::make_unique<Derived2>();
}

这就像中这样做非常烦人。

如果您在编译时不知道该DerClasses值,则这不起作用,并且无法正常工作。您可以获得的最接近的是延续传递风格:

template<class F>
decltype(auto) create_instance(DerClasses enum_class, F&& f){
  switch(enum_class) {
    case DerClasses::Derived1:
      return f(std::make_unique<Derived1>());
    case DerClasses::Derived2:
      return f(std::make_unique<Derived2>());
  }
}

使用如下:

create_instance(DerClasses::Derived1, [&](auto&& ptr) {
  if constexpr( std::is_same< std::decay_t<decltype(*ptr)>, Derived1 >{} )
    ptr->derived1_class_only_variable = 123;
});

但这也很糟糕,因为 lambda 是用两种派生类型调用的;只有一个在运行。

使用覆盖可能会起作用,但你又要疯了。


推荐阅读