1
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.

user3329769
  • 31
  • 1
  • 3
  • 1
    Constructor to set class members. – Kakalokia Feb 19 '14 at 20:02
  • 2
    It is not a good idea to have a function to set multiple members at the same time. – Victor Feb 19 '14 at 20:02
  • 1
    You could use member array – HEKTO Feb 19 '14 at 20:03
  • Are all of the members of the same type? – ALOToverflow Feb 19 '14 at 20:08
  • What sort of value do you consider `n` to be, to be large? It may be that a better design is on order. – Peter M Feb 19 '14 at 20:21
  • I mean, you COULD make a templated set method that takes a value and an enum, and similar for get. Use the enum to switch which value you're setting. That seems like a bad idea, though. Personally, I'm more comfortable with a lot of boring functions than trickery. As others mentioned, if n is large, and people need direct access to all of n, you might not be using the best design. – m24p Feb 19 '14 at 20:27
  • You are probably looking for a container here. For example, maybe you would be better off with a std::map, now you can get or set any of your members by accessing an element from the map by the string that represents that element. – YoungJohn Feb 19 '14 at 21:07
  • You need a level of abstraction over setters/getters. Some sort of Properties class, maybe where you can access the properties by 'name' or some other means. But we're not seeing your requirements here, just your own proposed solution (which is fine if that's what you want). – codah Feb 19 '14 at 21:07

5 Answers5

4

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.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Doesn't this assume all the members are int? – Kakalokia Feb 19 '14 at 20:04
  • 1
    @AliAlamiri Absolutely. As in OP's example. – juanchopanza Feb 19 '14 at 20:04
  • But he may have other types in the class not just ints. I also think to set the members he could just use a constructor. – Kakalokia Feb 19 '14 at 20:06
  • What happens when `index` falls outside of the range `0..N-1`? – Peter M Feb 19 '14 at 20:06
  • @PeterM Undefined behaviour. – juanchopanza Feb 19 '14 at 20:07
  • 1
    @juanchopanza And `Undefined behavior` is a good thing to have in a program? /sarcasm – Peter M Feb 19 '14 at 20:08
  • 1
    @AliAlamiri Could be. They haven't said that. I wrote this half in jest because the question is kind of nonsensical. One really shouldn't have a class with a zillion getters and setters. – juanchopanza Feb 19 '14 at 20:08
  • 1
    @PeterM One could add another version that checks the bounds and throws if necessary. Or one could throw the whole thing away and write sensible classes in the first place :-) – juanchopanza Feb 19 '14 at 20:11
  • @peterM - Perhaps throw an exception. But I have never could across an example with large numbers of getters or setters. – Ed Heal Feb 19 '14 at 20:11
  • @juanchopanza I worry about solutions written in jest as the OP may not know enough to realize that they are in jest (especially as the code sample is bad in itself). But a simple set/get throwing an exception sort of scares me even more. To me that sort of functionality should be restricted to a plain old method. – Peter M Feb 19 '14 at 20:13
  • @PeterM- What is wrong with throwing an exception? After all that it what they are for. – Ed Heal Feb 19 '14 at 20:15
  • @EdHeal I follow the philosophy that exceptions should be reserved for exceptional behavior. And to me testing that a user supplied index is in range is not exceptional. Now a hard drive crashing or the internet falling over - they are exceptional circumstances. – Peter M Feb 19 '14 at 20:17
  • @PeterM- In my book it is exceptional as the program should be written in a way the index should be in range in the first place. – Ed Heal Feb 19 '14 at 20:23
  • @PeterM I edited my answer. Hopefully OP will not implement my anti-solution. As for exceptions, it is customary for standard library containers to offer `at` methods that raise out of range exceptions in these cases. – juanchopanza Feb 19 '14 at 20:24
  • @EdHeal In which case you wouldn't need the exception :P – Peter M Feb 19 '14 at 20:29
  • @juanchopanza I may be a bit jaded right now as I have been working through some c# code written in the style of Java where every possible error status was indicated by an exception regardless if it was exceptional or not. – Peter M Feb 19 '14 at 20:32
  • @PeterM- Just in case a programmer makes a mistake. – Ed Heal Feb 19 '14 at 20:49
3

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
Ed Heal
  • 59,252
  • 17
  • 87
  • 127
1

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.

Ivan Aksamentov - Drop
  • 12,860
  • 3
  • 34
  • 61
1

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.

iavr
  • 7,547
  • 1
  • 18
  • 53
0

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.

Community
  • 1
  • 1
HEKTO
  • 3,876
  • 2
  • 24
  • 45