根据运行时值创建继承对象

Create inherited object based on runtime value

在 C++ 中有没有一种方法可以根据运行时参数创建 class 的实例?这是代码示例:

class base
{
public:
    base(int a) : a_(a) {}
    virtual void print()
    {
        cout << "base";
    }
    int a_;
};

class A : public base
{
    A(int a = 5) : a_(a), base(a) {}
    void print() override
    {
        cout << "class A";
    }
    int a_;
};

class B : public base
{
    B(int a = 6) : a_(a), base(a) {}
    void print() override
    {
        cout << "class B";
    }
    int a_;
};

int main(int argc, char** argv)
{
    int a = std::cin.get();
    base childClass(a);
    childClass.print();
}

现在假设当我在 std::cin 上输入 5 并调用 print() 时,它将打印“class A”。

我知道 A(int a = 5) 只是表示如果不传递任何参数,默认值将设置为 5,这只是为了更好地说明。

我不想要基于 if(a == 5) A a(5); a.print(); else if(a == 6) ...switch(a) ...

的解决方案

您的问题(C++ 中是否有一种方法可以根据 运行time 参数创建 class 的实例?)的简短回答是肯定的。对你不想要的回应是“不幸的是你别无选择。”

但是,通过在只需编写一次的函数中执行此操作可以缓解这种情况。下面的代码是一个简单的工厂示例。您将参数传递给工厂,它会创建所请求的对象。 C++ 工厂几乎总是必须 return 指向堆分配资源的指针才能在 运行 时运行。

智能指针,std::unique_ptr用于存储对象,这样我们就不必记得自己手动delete它了。

还有其他方法,例如资源池,但无论何时,您都需要 switchif/else 才能获得适当的资源。

#include <iostream>
#include <memory>

struct Base {
  virtual ~Base() = default;  // Required
  virtual void print() = 0;
};

struct A : public Base {
  void print() override { std::cout << "A\n"; }
};

struct B : public Base {
  void print() override { std::cout << "B\n"; }
};

struct C : public Base {
  void print() override { std::cout << "C\n"; }
};

Base* factory(char obj) {
  switch (obj) {
    case 'a':
      [[fallthrough]];
    case 'A':
      return new A;
    case 'b':
      [[fallthrough]];
    case 'B':
      return new B;
    case 'c':
      [[fallthrough]];
    case 'C':
      return new C;
    default:  // Could optionally throw to avoid the nullptr check in main()
      std::cerr << "Bad option given to factory\n";
      return nullptr;
  }
}

int main() {
  char want;
  std::cout << "Object: ";
  std::cin >> want;

  // Saves you having to manually `delete` the pointer
  std::unique_ptr<Base> obj(factory(want));

  if (obj) {
    obj->print();
  } else {
    std::cout << "Nothing\n";
  }
}

如果添加了新的子类型,新案例并不是什么大事,尽管您现在必须在两个地方更新代码。如果您将工厂与观察者之类的东西合并,这可以在一定程度上缓解。但无论如何,在某些时候你将不得不 if/elseswitch.