0

Please consider this class:

class A
{
public:       //public in this example
  string a1;
  string a2;
  string a3;
  string a4;
  int a5;
  double a6;
  (...) plus other 50 member names

  multiset<string> getAttrib(const vector(A)& va, string attr)
  {
    for (vector<string>::const_iterator ci = va.begin; ci != va.end(); ++ci) {
      cout << ci->attr << endl;     //ERROR
  }
};

The member function could be called like:

A a
a.getAttrib(vector_a, "a1");

This results in an error. Const class A has no member named 'attr'.

I didn't want to write 50 different case statements to achieve the above wanted flexibility. Is it possible somehow? And if member names are private can a public member function exist to perform this?

Besides class A, I have six other similar classes and wanted to have a parent class that would take a vector of any of the seven classes and could return the value (or in the real case a multiset) of the chosen membername.

Luis
  • 1,236
  • 5
  • 22
  • 31
  • 1
    Very similar to [How can I use Dynamic Methods in C++](http://stackoverflow.com/questions/1463515/how-can-i-use-dynamic-methods-in-c). – Matthew Flaschen Apr 06 '11 at 15:38
  • You seem to have Python or other languages in mind where members are just dictionary keys. That's not the case in C++. It is not possible to access members by a name that are not known at compile-time. – Alexander Gessler Apr 06 '11 at 15:40
  • @Alexander Gessler: Yes have previous experience in Python and Php. – Luis Apr 06 '11 at 16:10

3 Answers3

4

There's not a direct way to do what you want in C++, although there are some reasonable attempts at reflection frameworks out there. You might also look here: How can I add reflection to a C++ application? for additional commentary about reflection. I would suggest, however, that instead of having 50 member variables, you simply use one private std::hashmap and use std::string keys. You can then easily pass string parameters along as keys for direct lookups.

This, of course, assumes all your 50 members are of the same type, and that may not be suitable for your application. However, take my point, which is: do it a little differently.

Community
  • 1
  • 1
Ben Collins
  • 20,538
  • 18
  • 127
  • 187
  • The +50 member names (of different types) from each class match +50 fields in each table. One table = one class, one field = one member name. I guess I have to do it differently. Taking into account this, do you think that the hashmap is best suited for the job? – Luis Apr 07 '11 at 09:11
  • @Luis, it's hard to say without knowing the broader context of your problem and your approach to its solution. It sounds like your class is either a pass-through for transactional DB operations, or perhaps a mutable, volatile representation of the tables. Or maybe you're writing an ORM. I dunno. `std::hashmap` could be a very suitable data structure for any of that. It just depends on what you're doing and why. On the other hand, you may be reinventing the wheel, and should be using ODBC or OLE or http://stackoverflow.com/questions/74141/good-orm-for-c-solutions, or something similar. – Ben Collins Apr 07 '11 at 17:40
2

You could use the X macro technique to map variables to indices of a container (e.g. a std::deque) that would contain your a_n. You should probably add an extra entry at the end which you could use to get the needed container size.

Benjamin Bannier
  • 55,163
  • 11
  • 60
  • 80
0

It sounds like you might want a pointer-to-member, although it might be better to change to a more flexible object representation, such as an array of discriminated unions (boost::variant) or C++11 std::tuple.

Anyway, with pointer-to-member, you could have

  template< typename Attr_Type >
  static vector< Attr_Type > getAttrib(const vector<A>& va, Attr_Type A:: *attr)
  {
    vector< Attr_Type > ret;
    for (vector<A>::const_iterator ci = va.begin(); ci != va.end(); ++ci) {
      cout << ci->*attr << endl;
      ret.push_back( ci->*attr );
    }
    return ret;
  }

use as

vector< A > vector_a;
vector< string > vector_a_a1 = A::getAttrib(vector_a, &A::a1);
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421