C++: Iterating through all of an object's members? C++遍历成员变量

转载 2016年05月31日 09:15:22

转自:http://stackoverflow.com/questions/7142532/c-iterating-through-all-of-an-objects-members

Suppose I have an object with many members:

class Example {
    AnotherClass member1;
    AnotherClass member2;
    YetAnotherClass member3;
    ...
};

Is there a short/concise way to do something like:

foreach(member m: myExample)
    m.sharedMethod();

Instead of accessing each one individually?

I think I could put them in a vector and use a shared_ptr for the same effect, I was just wondering if say, Boost or some other popular library doesn't have something to do this automatically.

shareimprove this question
 
2  
I really don't think that this is a good idea. If you need to iterate through something, then declare it as an iteratable container, or why would you not do this? – leftaroundabout Aug 22 '11 at 2:18
 
check out Boost serialization – Cheers and hth. - Alf Aug 22 '11 at 2:19
1  
C++ doesn't have reflection. That means it's not possible. – Ryan Amos Aug 22 '11 at 2:22
6  
Out of curiosity, how would this even be useful? Often when something is so fundamentally impossible it's because it wouldn't make sense in the first place. – Kerrek SB Aug 22 '11 at 2:30

6 Answers

up vote10down voteaccepted

C++ does not support class introspection, so you cannot iterate over all of the members in a class like that - not without having a (manually written) function that iterates over all members for you anyway.

You could, in principle, add a template member like so:

template<typename Functor>
void doAllMembers(Functor &f) {
  f(member1);
  f(member2);
  f(member3);
}

That said, I would regard this as a broken design; you've gone and exposed all of your internal members publicly. What happens if you add one later? Or change the semantics of one? Make one a cached value that's sometimes out of date? etc. Moreover, what happens if you have members which don't all inherit from the same types?

Step back and reconsider your design.

shareimprove this answer
 

There are several solutions to this issue, contrary to what the naysayers blabber, but no built-in way.

C++ support a limited kind of introspection, at compile-time: you can check the template parameters.

Using either Boost.Tuple or Boost.Fusion (for its map), you can indeed achieve what you wish. In Boost.Fusion you even have BOOST_FUSION_ADAPT_STRUCT to transform a basic structure into a Fusion Sequence (and thus iterate it).

It requires quite a bit of template meta-programming though.

shareimprove this answer
 
 
Liked this solution. Posted the detailed code here: C++ iterate into nested struct field with boost fusion adapt_struct – minghua Sep 6 '12 at 7:04

C++ can do something like this, if you play by its rules and use template metaprogramming.

Instead of storing your stuff in a struct or class, store it in a tuple:

typedef boost::tuple<AnotherClass, AnotherClass, YetAnotherClass> Example;

Then you can use template metaprogramming algorithms and so forth (see Boost.Fusion) to access members and poke at stuff. You can iterate, template-style, over the elements of the tuple.

shareimprove this answer
 

It is possible that what you're looking for here is the Visitor pattern. If you have an object as you describe, with a number of non-trivial member fields, and you find that you have a number of different functions that all traverse this data structure in the same way, the visitor pattern can be very helpful in reducing the amount of code duplication. It is not automatic, through, you have to write the functions that traverse all the member fields, but you only have to do that once, and you can use it many times over with different visitor classes that do different things.

The visitor pattern does involve writing quite a bit of code, you need an abstract base class for the visitors:

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 ...
};

Then you need accept functions in all the classes that are going to be visited:

void Example::accept( VisitorBase& visitor ) 
{
    visitor.enter(*this);
    member1.accept(visitor);
    member2.accept(visitor);
    member3.accept(visitor);
    visitor.leave(*this);
}

And finally you need to implement concrete visitor classes that do the actual work you're interested in, which generally amounts to gather information from the data structure, making changes to the data structure, or combinations of both. Google Visitor pattern and you'll find lots of help on this.

shareimprove this answer
 

This is my way to do what you want to achieve in C++11. It uses tuple and templates. It's not short and concise but if you wrap somecode in a header file is acceptable. There is my full compilable example:

#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);
}
shareimprove this answer
 

This is not possible with C++, if you really Really REALLY need this then instead use C#. But I seriously doubt you do.

Having said that, about the only option you really have is to use .NET and use managed C++ which microsoft calls Managed C++/CLI. But the caveat, is your class must be a managed 'ref class', meaning a managed class. Eventually it all gets compiled down to MSIL, and intermediate language that is language agnostic. That's the only way you could then use .NET reflection on it at runtime to discover it's member functions and values. However even using .NET it's not as easy as you described how you would like to use it above. Another downside to reflection is that it's slow, so if you are using it heavily you have a bad design. Reflection is nice in that .NET uses it to help in serializing data types, which makes XML serialization very easy to use.


c++ STL List查找遍历及各成员函数用法详细介绍

c++ STL List将元素按顺序储存在链表中. 与 向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢.c++ STL List就是一双向链表,可高效地进行插入删除元素。包...
  • yuzeze
  • yuzeze
  • 2016年06月13日 10:48
  • 6699

如何用C++获取运行时变量的类型

如何用C++获取运行时变量的类型 www.educity.cn   发布者:evilbat   来源:网络转载   发布日期:2013年12月25日    在上数据库实现技术的时候,老师提...
  • lfang0222
  • lfang0222
  • 2016年08月09日 15:15
  • 554

C++ List的用法(整理)

Lists将元素按顺序储存在链表中. 与 向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢. assign() 给list赋值  back() 返回最后一个元素 ...
  • lskyne
  • lskyne
  • 2013年08月27日 23:04
  • 167031

Win7 x64 Vad遍历模块

Win7x64 Vad遍历模块
  • zhuhuibeishadiao
  • zhuhuibeishadiao
  • 2016年12月06日 16:46
  • 1385

Runtime-遍历类的成员名称和类型

1、创建一个Person类 #import @interface Person : NSObject { CGFloat height; } @property (nonatomic, ...
  • PoLuoGuiZu
  • PoLuoGuiZu
  • 2014年04月18日 17:20
  • 1252

c++类中成员变量的初始化总结

关于这个问题是引起来源于一则面试问题:引用型成员变量如何初始化?回答的不是很确定,于是对这个问题研究一下。 1、普通的变量:一般不考虑啥效率的情况下 可以在构造函数中进行赋值。考虑一下效率的可以再构造...
  • jenghau
  • jenghau
  • 2009年10月31日 22:30
  • 9396

HP小型机故障诊断

  • zgqtxwd
  • zgqtxwd
  • 2008年04月26日 19:56
  • 176

采样问题

问题描述 从0~n-1中随机选取m(m < n)个不同整数,且使m个整数有序输出。 已知条件 bigRand()产生一个远大于m和n的正整数; randInt(int i,int j)产生一个[i,j...
  • sunzhifeng1989
  • sunzhifeng1989
  • 2015年04月08日 11:06
  • 448

ObjectModel:Qml 使用C++model

用QList 来实现model 官方为何叫做ObjectModel 打比方有一个QObject* obj ; Q_INVOKABLE QVariant _get() { ...
  • A289672082
  • A289672082
  • 2016年07月15日 13:44
  • 1378

引用作为C/C++ - 类中成员变量

引用作为C/C++ - 类中成员变量 转自:http://blog.csdn.net/lazyq7/article/details/48186291 引用作为成员变量: 不能有默认构造函数必须提...
  • shuixiaowei0530
  • shuixiaowei0530
  • 2017年06月15日 17:12
  • 424
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++: Iterating through all of an object's members? C++遍历成员变量
举报原因:
原因补充:

(最多只允许输入30个字)