C++:遍历对象的所有成员?
C++: Iterating through all of an object's members?
假设我有一个有许多成员的对象:
class Example {
AnotherClass member1;
AnotherClass member2;
YetAnotherClass member3;
...
};
有没有一种更简洁的方式来做某事,比如:
foreach(member m: myExample)
m.sharedMethod();
而不是单独访问每个?
我想我可以把它们放在一个矢量中,并使用shared_ptr
来达到同样的效果,我只是想知道是否说,Boost或其他流行的库没有自动做到这一点。
c++不支持类自省,所以你不能像那样遍历类中的所有成员——除非有一个(手动编写的)函数为你遍历所有成员。
原则上,您可以像这样添加模板成员:
template<typename Functor>
void doAllMembers(Functor &f) {
f(member1);
f(member2);
f(member3);
}
也就是说,我会认为这是一个失败的设计;你把你所有的内部成员都公开了。如果稍后再加一个会怎么样?或者改变一个的语义?使一个缓存值有时是过时的?等。此外,如果成员并非全部继承自相同类型,会发生什么情况?
这个问题有几个解决方案,与反对者的喋喋不休相反,但没有内置的方法。
c++在编译时支持一种有限的自省:你可以检查模板的形参。
使用Boost.Tuple
或Boost.Fusion
(用于其地图),您确实可以实现您的愿望。在提高。你甚至有BOOST_FUSION_ADAPT_STRUCT将基本结构转换为融合序列(从而迭代它)。
它需要相当多的模板元编程
c++可以做类似的事情,如果你遵守它的规则并使用模板元编程。
不要将数据存储在结构体或类中,而是将其存储在元组中:
typedef boost::tuple<AnotherClass, AnotherClass, YetAnotherClass> Example;
然后你可以使用模板元编程算法等等(参见Boost.Fusion)来访问成员并戳东西。您可以以模板样式遍历元组中的元素。
您在这里寻找的可能是Visitor模式。如果您有一个对象,如您所描述的,具有许多重要的成员字段,并且您发现您有许多不同的函数,它们都以相同的方式遍历这个数据结构,那么访问者模式可以非常有助于减少代码重复的数量。这不是自动的,因为你必须编写遍历所有成员字段的函数,但你只需要做一次,你可以在做不同事情的不同访问者类中多次使用它。
访问者模式确实涉及编写相当多的代码,您需要为访问者提供一个抽象基类:
class VisitorBase
{
virtual void enter(Example& e)=0;
virtual void leave(Example& e)=0;
virtual void enter(AnotherClass& e)=0;
virtual void leave(AnotherClass& e)=0;
etc ...
};
那么你需要接受所有将要访问的类中的函数:
void Example::accept( VisitorBase& visitor )
{
visitor.enter(*this);
member1.accept(visitor);
member2.accept(visitor);
member3.accept(visitor);
visitor.leave(*this);
}
最后,您需要实现具体的访问者类来完成您感兴趣的实际工作,这通常相当于从数据结构中收集信息,对数据结构进行更改,或者两者的组合。谷歌访问者模式,你会在这方面找到很多帮助。
这是我在 c++ 11中实现的方法。它使用元组和模板。它并不简短,但如果您将一些代码包装在头文件中是可以接受的。这是我完整的可编译示例:
#include <iostream>
#include <string>
using namespace std;
#include <tuple>
//Our iteratation code
//first a iteration helper structure
template<int N = 0>
struct IterateP {
template<class T>
typename std::enable_if<(N < std::tuple_size<T>::value), void>::type
iterate(T& t) {
std::get<N>(t).sharedMethod(); //there is the method name
IterateP<N+1>().iterate<T>(t);
}
template<class T>
typename std::enable_if<!(N < std::tuple_size<T>::value), void>::type
iterate(T&) {}
};
//wrapper of the helper structure for a more comfortable usage
template <typename T>
void iterate(T& t) { IterateP<>().iterate(t.members); } //look at the .members, is the name of the class tuple
//Helper notation macro.
#define MEMBER(name, i) std::tuple_element<i,decltype(members)>::type &name = std::get<i>(members)
//YOUR CLASSES
struct AnotherClass {
int value;
void sharedMethod() { cout << value << endl; }
};
struct YetAnotherClass {
string value;
void sharedMethod() { cout << value << endl; }
};
//The class with iterable members
struct Example {
std::tuple<AnotherClass, AnotherClass, YetAnotherClass> members; //members must be in a tuple
//These are helper member definition to access the tuple elements as normal members (instance.member1)
//If you don't you this you need to access the members with tuple classes
MEMBER(member1, 0); //first param is the member name and the second is it's position in the tuple.
MEMBER(member2, 1);
MEMBER(member3, 2);
};
//USAGE
int main() {
Example example;
//setting members just as a normal class
example.member1.value = 1;
example.member2.value = 2;
example.member3.value = "hola";
//magic
iterate(example);
}
这在c++中是不可能的,如果你真的真的真的需要这个,那就用c#吧。但我很怀疑你是否知道。
说到这里,你唯一的选择就是使用。net和managed c++,微软称之为managed c++/CLI。但是需要注意的是,你的类必须是一个托管的ref类,意思是一个托管类。最终,所有这些都被编译成MSIL,以及与语言无关的中间语言。这是在运行时使用。net反射来发现它的成员函数和值的唯一方法。然而,即使使用。net也不像你上面描述的那样简单。反射的另一个缺点是它很慢,所以如果你大量使用它,你的设计就会很糟糕。反射很好,因为. net使用它来帮助序列化数据类型,这使得XML序列化非常容易使用。
- 有什么方法可以遍历结构吗
- 在循环中按顺序遍历成员变量
- 遍历模板参数
- 在遍历处理程序的向量时注册和注销处理程序
- C++RapidXml-使用first_node()遍历以修改XML文件中节点的值
- 遍历并行数组以确定C++中的最大数字
- 遍历顺序由 std::文件系统directory_iterator给出
- 遍历链表时的无限循环
- 遍历unordered_map向量
- 从预序遍历构造 bst 的 c++ 和 python 解决方案之间的区别
- C++声明双链表,使用两个 for 循环双向遍历列表并打印
- Rapidjson 遍历并获取复杂 JSON 对象成员的值
- 在使用 In Order 遍历成员函数时引发异常(堆栈溢出)时出现问题
- 如何调用遍历类层次结构的成员函数
- 是否可以在 constexpr 函数中遍历枚举成员,因此值为 constexpr
- 如何遍历类的实例集合并访问其模板成员
- 在向量中遍历结构成员时出错
- 遍历对类成员的引用,简单且最好是可重用的
- 使用引用的数组 (C++) 遍历类成员
- C++:遍历对象的所有成员?