查找类的成员变量列表及其类型?

7
我从未听说过这是可能的,但希望询问一下。
对于一个具有比这个更多成员变量的类:
class A
{
 public:
  SomeOtherClass* s;
  int i;
  int j;
  A() {}
  A(const A& soc): s(soc.s->Clone()), i(soc.i), j(soc.j) {}
};

我必须记住,如果我向类中添加另一个变量int k,我也必须在初始化列表k(soc.k)和有时在析构函数中添加它。我不断地添加/删除成员变量,忘记在初始化列表中复制它们并在调试时很久以后发现遗漏,这真的很烦人。
因此,我想知道是否有一种语法/逻辑可以找出类的成员变量列表及其类型,这样我就可以遍历它们并决定哪些需要在复制构造函数中复制,哪些需要进行深度复制?
我不明白为什么C++的创建者不能包含这样的功能,因为除了虚拟成员外,变量的内存位置是连续的,它们的类型也是已知的。即使它们是extern或virtual,类型和大小也会在运行时知道。所以这不应该是可能的吗?
6个回答

13

C++中没有反射功能,因此您需要使用外部库来实现。 C++的创建者没有实现这个功能,因为它会带来性能损失,而性能是C++的主要目标之一。


有没有外部库?除了不能使用初始化列表的奢侈之外,还会有什么性能损失吗?但是有选择使用初始化列表是使C++强大的原因。我没有看到任何其他因素可以因为性能问题而省略它。 - Nav
2
根据谷歌的搜索结果,是的(XCppRefl排名第一)。虽然我从未尝试过这些库,但你可能想问一个关于哪个库最好的单独问题。 - dario_ramos
好的,哪个库是最好的 :) - Nav
我不知道 :P 你应该在一个单独的、新的问题中问。还有一些建议:我认为使用反射来解决这个问题是过度的。正如他们在另一个问题中所说,代码审查和单元测试是捕捉此类错误的更好选择。 - dario_ramos
1
关于性能损耗:要实现反射,你需要在某个地方存储每个类的元数据,这就是主要原因。好吧,它可能是可选的,初始化列表也是一样,但我相信Bjarne在这方面很有经验,他知道自己在做什么。 - dario_ramos

3
我需要记住,如果我向类中添加另一个变量int k,我还需要在初始化列表k(soc.k)和有时在析构函数中添加它。
是的,你需要。
我已经多次添加/删除成员变量,忘记了在初始化列表中复制,并且在调试时找到遗漏实在很烦人。
是的,确实如此。
因此,我想知道是否有一种语法/逻辑可以查找类的成员变量及其类型的列表,以便我可以通过它们进行迭代,并决定哪些需要在复制ctor中复制,哪些需要进行深度复制?
不,没有这样的功能。
我不明白为什么C ++的创建者不能包括这样的设施,因为除了虚成员外,变量的内存位置将是连续的,并且它们的类型也是已知的。即使它们是extern或virtual,类型和大小也将在运行时得知。那么这不可能吗?
理论上是可以的。
C++并不是真正意义上的“那种语言”,但它确实有点麻烦。

2

2
很惊讶看到有人踩了我点赞的答案。不管是谁,你为什么这样做呢?我认为Ali给出了关于反射概念的正确链接。 - Nav
2
我也认为这是一个有建设性的回答,因为链接中包含了对问题的明确回答。给出负评的人,请友善地写下你的原因,如果我错了,我会自行修正。 - Hayri Uğur Koltuk
有趣的链接,但有点过时:它来自2009年,在C++11升级之前。(没有投反对票;)) - Pellekrino

1

是的,这并不能回答你的问题,但为了解决你的问题,在我的代码中我使用了一个结构体来保存可以自动复制的成员,这样我就不用担心它们了。

class A
{
 public:
  SomeOtherClass* s;

  class Members
  {
    int i;
    int j;
  };

  Members m;

  A() {}
  A(const A& soc): s(soc.s->Clone()), m(soc.m) {}

  void f() {
    m.j;//use j
  }
};

但通常我更喜欢使用deep_copy指针,这样我甚至不需要那个技巧(当我可以时,指针也会自动复制)。

我之前发过一篇帖子:https://stackoverflow.com/questions/469696/what-is-your-most-useful-c-c-utility/1609496#1609496

我不确定这是否能解决您的析构函数问题(也许deep_copy指针可以)。

如果您感兴趣,我还建议查看在stackoverflow上谈论memberspace的帖子,如果我没记错的话,它基本上是为其他目的使用相同类型的技巧。


0

正如所述,C++ 中没有反射机制。你可以做的一个简单的事情是检查类的大小。这样至少可以通过生成错误消息来使你查看正确的位置,如果你忘记在添加成员后更新大小。

例如:

template<size_t Real, size_t Expected> struct check_size;
template<size_t Size> struct check_size<Size, Size> {};
// ...
A(const A& soc): s(soc.s->Clone()), i(soc.i), j(soc.j) {check_size<sizeof(A), 24> size_checker;}

0
我总是要记住,如果我向类中添加另一个变量int k,我也必须在初始化列表k(soc.k)中添加它,有时还要在析构函数中添加。

不,你不需要这样做。只需将所有内容公开,并且不提供构造函数和析构函数。聚合初始化会处理它。如果您需要某些私有内容,则意味着您具有封装性,并且无论字段如何,构造函数列表都应该固定。

如果您担心资源泄漏,请使用RAII模式,在指针的情况下使用std::unique_ptrstd::shared_ptr

现在关于标题:

查找类的成员变量及其类型列表?

如果您可以使用聚合初始化,那么有一个超级酷的仅限模板(无宏)库boost pfr可以完成此操作。

这里有一个演讲,库的作者在演讲中解释了它的工作原理。


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