根据运行时值创建继承对象
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
它了。
还有其他方法,例如资源池,但无论何时,您都需要 switch
或 if/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/else
或 switch
.
在 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
它了。
还有其他方法,例如资源池,但无论何时,您都需要 switch
或 if/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/else
或 switch
.