通过名称创建对象

发布于 2024-10-12 06:08:41 字数 539 浏览 7 评论 0原文

是否可以使用 C++ 中传递的类型名称(字符串)返回对象的示例? 我有一些基本抽象类 Base 和一些派生类。示例代码:

class Base
{
   /* ... */
};

class Der1 : public Base
{
   /* ... */
};

class Der2 : public Base
{
   /* ... */
};

我需要这样的函数:

Base *objectByType(const std::string &name);

派生类的数量是可变的,我不想进行类似切换 name 并手动返回新对象类型的操作。无论如何,在 C++ 中是否可以自动执行此操作?

ps 用法应该如下所示:

dynamic_cast<Der1>(objectByType("Der1"));

我需要纯 C++ 代码(跨平台)。使用升压是允许的。

is it possible to return exemplar of object using passed type name (string) in c++?
I have some base abstract class Base and a few derivates. Example code:

class Base
{
   /* ... */
};

class Der1 : public Base
{
   /* ... */
};

class Der2 : public Base
{
   /* ... */
};

And I need function like:

Base *objectByType(const std::string &name);

Number of derivates classes are changeable and I don't want to make something like switching of name and returning by hands new object type. Is it possible in c++ to do that automatically anyway?

p.s. usage should looks like:

dynamic_cast<Der1>(objectByType("Der1"));

I need pure c++ code (crossplatform). Using boost is permissible.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

七禾 2024-10-19 06:08:41

有一个很好的技巧,可以让你编写一个没有 if 序列的 工厂方法 ...否则如果...

(请注意,AFAIK,确实不可能在 C++ 中执行您想要的操作,因为此代码是在编译时生成的。“工厂方法”设计模式就是为此目的而存在的)

首先,为派生类定义一个全局存储库。它可以采用std::map 的形式,即将派生类的名称映射到该类的实例

对于每个派生类,您定义一个默认构造函数,它将该类的对象添加到类名称下的存储库中。您还定义了该类的静态实例:

// file: der1.h
#include "repository.h"

class Der1: public Base {
public:
  Der1() { repository[std::string("Der1")] = this; }
};

// file: der1.cpp
static Der1 der1Initializer;

静态变量的构造函数甚至在 main() 之前运行,因此当您的 main 启动时,您已经使用以下实例初始化了存储库所有派生类。

您的工厂方法(例如Base::getObject(const std::string&))需要在存储库映射中搜索类名。然后,它使用找到的对象的 clone() 方法来获取相同类型的新对象。您当然需要为每个子类实现clone

这种方法的优点是,当您添加新的派生类时,您的添加仅限于实现新类的文件。存储库和工厂代码不会改变。当然,您仍然需要重新编译您的程序。

There is a nice trick which allows you to write a factory method without a sequence of if...else if....

(note that, AFAIK, it is indeed not possible to do what you want in C++ as this code is generated in the compile time. A "Factory Method" Design Pattern exists for this purpose)

First, you define a global repository for your derived classes. It can be in the form std::map<std::string, Base*>, i.e. maps a name of the derived class to an instance of that class.

For each derived class you define a default constructor which adds an object of that class to the repository under class's name. You also define a static instance of the class:

// file: der1.h
#include "repository.h"

class Der1: public Base {
public:
  Der1() { repository[std::string("Der1")] = this; }
};

// file: der1.cpp
static Der1 der1Initializer;

Constructors of static variables are run even before main(), so when your main starts you already have the repository initialized with instances of all derived classes.

Your factory method (e.g. Base::getObject(const std::string&)) needs to search the repository map for the class name. It then uses the clone() method of the object it finds to get a new object of the same type. You of course need to implement clone for each subclass.

The advantage of this approach is that when you are adding a new derived class your additions are restricted only to the file(s) implementing the new class. The repository and the factory code will not change. You will still need to recompile your program, of course.

初心未许 2024-10-19 06:08:41

在 C++ 中不可能做到这一点。

一种选择是编写一个工厂并打开传入的名称,但我发现您不想这样做。除了dynamic_cast之外,C++不提供任何真正的运行时反射支持,因此此类问题很难解决。

It's not possible to do this in C++.

One options is to write a factory and switch on the name passed in, but I see you don't want to do that. C++ doesn't provide any real runtime reflection support beyond dynamic_cast, so this type of problem is tough to solve.

妞丶爷亲个 2024-10-19 06:08:41

是的,这是可能的!检查这个非常有趣的类,名为 <代码>激活器
您可以通过 Typestring 创建所有内容,甚至可以给出参数列表,因此该方法将使用最佳参数集调用适当的构造函数。

Yes that is possible! Check this very funny class called Activator
You can create everything by Type and string and can even give a List of parameters, so the method will call the appropriate constructor with the best set of arguments.

通知家属抬走 2024-10-19 06:08:41

这是不可能的。您必须自己编写 objectByType 函数:

Base* objectByType(const std::string& name) {
  if (name == "Der1")
    return new Der1;
  else if (name == "Der2")
    return new Der2;
  // other possible tests
  throw std::invalid_argument("Unknown type name " + name);
}

It is not possible. You have to write the objectByType function yourself:

Base* objectByType(const std::string& name) {
  if (name == "Der1")
    return new Der1;
  else if (name == "Der2")
    return new Der2;
  // other possible tests
  throw std::invalid_argument("Unknown type name " + name);
}
你怎么敢 2024-10-19 06:08:41

C++ 不支持反射

在我看来,这是 Java 击败 C++ 的一点。
(希望不要为此获得太多反对票...)

您可以通过使用自定义预处理器来实现类似的目标,类似于 MOC 对 Qt 的做法。

C++ doesn't support reflection.

In my opinion this is the single point where Java beats C++.
(ope not to get too many down votes for this...)

You could achieve something like that by using a custom preprocessor, similar to how MOC does for Qt.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文