C++:在运行时创建类

6
我有一个问题,我有一组扁平文件(例如file1、file2等),其中包含列名和本地数据类型。(如何存储值并在c++中读取是基础知识)例如,扁平文件file1可能具有以下数据: col1_name=id,col1_type=integer,col2_name=Name,col2_type=string等等。
因此,对于每个扁平文件,我需要创建C++数据结构(即1个扁平文件=1个数据结构),其中成员变量名称与列名相同,其数据类型将根据扁平文件中的列类型为C++本机数据类型,例如int、float、string等。根据上面的示例:我的扁平文件1应该给我以下声明。
class file1{
  int id;
  string Name;
};

有没有办法在C++中编写代码,创建的二进制文件可以读取平面文件并基于该文件创建数据结构(类名与平面文件名相同)。所有使用这些平面文件创建的类都将具有获取器和设置器成员函数的共同功能。

如果您以前做过类似的事情或对此有任何想法,请告诉我。


2
不可能的,抱歉。你需要使用类似于字符串映射(属性名称)到变量数据类型的东西。 - Jon
1
在C++中无法在运行时创建类定义,但可以使用脚本语言甚至C++来读取这些平面文件并输出源文件,稍后再进行编译。 - parapura rajkumar
我从未使用过 boost::any。那会帮助解决 @rocky 的问题吗? - Robᵩ
我脑海中一直在思考一个想法。基本上,您不会完全将类集成到软件中,而是让软件创建一个(更简单的)新程序,编译它,然后通过运行它来使用它,这应该是可行的。但我并不100%确定... - John Harlan
6个回答

9

不,不容易(请参见其他 答案以了解原因)。

我建议看看Python,它更适合解决这种问题。Python的类型系统结合使用try/except的理念更容易解析数据。

如果您非常必须使用C ++,则可以使用QtQObject类的动态属性特性结合QVariant类找到解决方案。虽然这样做可以实现您想要的功能,但我会添加一个警告,即这种方法可能会使任务变得复杂和繁重。

@downvoter,您能解释一下为什么这不是有用的吗?它清楚地说“如果您曾经做过类似的事情或对此有任何想法,请告诉我。” - Samuel Harmer
我也是 - 我和你一起 - (+1) - Andrey Rubshtein
1
@Styne666:我不知道是谁做的,也不知道为什么,但对我来说,这个答案至少缺少一些简短的解释,说明为什么Python更好。现在看起来有点像宠物语言广告。 - PlasmaHH
@PlasmaHH 我并不倡导偏爱某种编程语言。然而,显而易见的是,有些语言在某些方面比其他语言更擅长;这正是一个典型的例子。我根据问题的详细程度来评估我的回答,但为了满足你的要求,我已经添加了一些关于下一步研究的指引。 - Samuel Harmer
1
@Styne666:赞同。这也会满足那些不了解Python的人,使得代码更加易懂明了。 - PlasmaHH
@PlasmaHH是正确的;最初这不是对已经提出的问题的回答,而是一种“只需使用另一种语言”的回应,并不完全有帮助。但是,现在它解决了问题的具体细节,非常棒。 :) - Lightness Races in Orbit

8
不可以直接编译C++ 转换的文件,需要分为两步。首先,编写一个程序来读取这些文件并将其翻译成 .cpp 文件。然后,将这些 .cpp 文件传递给编译器进行编译。

2
@Seth:这就是为什么我回答的第一个词是“不”。然而,你可以将这段代码编译成DLL并动态加载它。这有用吗?从这个问题中我无法判断。 - MSalters
编译和加载dll的想法真是太棒了,不错。这可能是我当前项目中一个有趣的实验性解决方案。 - Iron Attorney

6

C++类是一种纯粹的编译时概念,没有在运行时意义,因此不能被创建。但是,您可以选择:

std::vector<std::string> fields;

在您的访问函数中进行必要的解析。


2
boost::any 可能比 std::string 更好。 - Mooing Duck

5
不是的,但据我所知,你必须能够存储多个列的名称。你可以使用成员变量mapunordered_map,通过字符串索引它们 - 列的名称 - 并获取一些数据(例如列对象之类的)。这样你就可以这样做:
obj.Columns["Name"]

0

我不确定这是否有一个设计模式,但如果你的可能类型名称列表是有限的,并且在编译时已知,那么你不能在运行之前声明所有这些类,并根据文件中的数据实例化它们吗?


大家好,感谢回复我的问题并帮助我。我的主要关注点是实现单个二进制文件并将其发送给不同的客户端。由客户提供的扁平文件结构将是不同的,因此该二进制文件应该是通用的,可以在运行时处理数据结构。当然,二进制文件的主要功能对于所有客户端都是相似的,除了我们需要处理客户端提供的不同数据,因此这是一个混乱的问题。我希望我的观点很明确。我认为这可能可以使用C++中的元编程或反射来实现,但我对这些概念还很陌生。 - user1138939
我认为你应该将那些文本文件视为要解析的输入。个人建议使用union来存储数据。但是,当然,在处理文本文件之前,你必须事先知道期望的内容,并考虑能够包含所有不同数据的结构,否则它将无法正常工作。 - Mr Lister

0

你实际上需要的是一个在运行时具有不同特性的字段。

有几种方法,包括 Boost.Any,但由于 C++ 类型系统的静态性质,只有两种方法真正推荐使用,并且都需要事先了解可能需要的所有可能数据类型。

第一种方法很典型:

  • Object 基础类型
  • IntStringDate 等派生类型

以及使用多态性。

第二种方法需要一些 Boost 魔法:boost::variant<int, std::string, date>

一旦你掌握了“variant”部分,就需要实现访问来区分不同的可能类型。传统面向对象方法的典型访问者或仅适用于 boost 方法的 boost::static_visitor<>boost::apply_visitor 组合。

这相当简单。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接