user3329769
user3329769

Reputation: 31

C++ class function to get/set multiple members

Class classname
{
    int member1;
    int member2;
    ...
    int membern;
    public:
        void setmember1(int);
        void setmember2(int);
        ...
        void setmembern(int);

        void getmember1(int);
        void getmember2(int);
        ...
        void getmembern(int);
}

I know that I can define 2n class functions to get and set n specified member values in-place for the declarations above.

However, this seems needlessly tedious when n is large. Is there a good way to define one class function that takes an extra argument to set/get any member of the class?

EDIT: Syntax errors aside, my rationale for large n is to preserve the scientific framework behind the class. For example, say the class is enzyme. So I'd prefer to keep its properties in the same place and not index by number unless absolutely necessary.

Set/get functions are public because they're called in a different class (that sets up a GUI).

And, no, not all the members are ints. I copy-pastaed for the sake of simplicity.

Upvotes: 1

Views: 2768

Answers (5)

iavr
iavr

Reputation: 7637

I am no fun of setters/getters, although they are quite common in applications like a GUI. Anyhow, I have a generic solution that does require a library and is probably an overkill for this problem. Assume you have the following class

 class A
 {
    char   member1;
    int    member2;
    double membern;

 public:
    void set_member1(char c)   { member1 = c; }
    void set_member2(int i)    { member2 = i; }
    void set_membern(double d) { membern = d; }

    char   get_member1() { return member1; }
    int    get_member2() { return member2; }
    double get_membern() { return membern; }
 };

You can then write

    auto val = _('c', 42, 3.14);
    auto set = _(&A::set_member1, &A::set_member2, &A::set_membern);
    auto get = _(&A::get_member1, &A::get_member2, &A::get_membern);

    A a;
    (a ->* set)(val);
    cout << (a ->* get)() << endl;

which prints

(c, 42, 3.14)

That is, you are working with tuples. Syntax _(...) represents a tuple; val is a tuple of values (possibly of different types) and set/get are tuples of pointers to members. Operator ->* in the syntax given above allows calling multiple member functions on a single object with multiple arguments, one argument per function. The result of the call to get is again a tuple of values.

For all this to work, you need library ivl that I am currently developing. The syntax above is just a small sample; the library is much more flexible, allowing to define functions or operators for scalars and then call them on tuples or arrays, in any combination. All C++ operators are overloaded to allow this kind of "vectorization". Operator ->* can also work with function objects apart from pointers to members, so that calls are inlined. It also allows the alternative syntax

    a ->* set._(val);
    cout << a ->* get._() << endl;

so that member functions bind with arguments first, before being applied to the object(s). Member functions can have as many arguments (of any type) as you like, but all should have the same number of arguments in a single call.

Upvotes: 1

HEKTO
HEKTO

Reputation: 4191

You touched an old problem with C++, which is very limited reflection functionality in the language. The discussion below is worth to look at in case you came from a language with reflection:

How can I add reflection to a C++ application?

As for a practical advice, all other answers given here make perfect sense.

Upvotes: 0

juanchopanza
juanchopanza

Reputation: 227390

In real code you should not have classes with many data members, and certainly not individually settable and gettable ones.

You could achieve what you are asking for using an array:

class classname
{
 public:
  setMemberDangerously(size_t index, int value) { data[index] = value; }
  setMember(size_t index, int value)
  {
    if (! index < size) throw std::out_of_range("Index out of bounds");
    data[index] = value;
  }
 private:
  int data[N];
};

But now your class looks like a collection, in which case you might as well use a standard library container.

Upvotes: 4

Drop
Drop

Reputation: 13005

You can invent any tools to make your bad-designed classes "almost manageable". If it's hard to write getters/setters, don't do this. Your class must be refactored.

General solution here is to avoid big values of n

Design your classes to preserve single responsibility principle. Avoid god-classes.

Upvotes: 1

Ed Heal
Ed Heal

Reputation: 59997

Either:

  1. Write a script to generate the methods
  2. Put all those integers into an array and use one get/set with an index

EDIT

Besides your get should be

int getX() const;

EDIT

Thought of another two possibilities

  1. Overload the [] operator
  2. Inherit from std::vector

Upvotes: 3

Related Questions