9

I am not familiar with templates, but I wonder, if it is possible to use them for setter and getter methods. For example in this situation:

double exmlClass::getA(void) const
{
    return a_;
}



void exmlClass::setA(const double& a)
{
    a_ = a;
}



double exmlClass::getB(void) const
{
    return b_;
}

As you can see, methods are almost the same, except they refer to another private variables (a_, b_, c_). Is there a more elegant way to write those functions or it is common practice to do like above in such situations? And if its common to use templates, I would appreciate example how you would use them in code above.

Another question I would ask is how should getters and setters be properly declared. Is it good coding style?

double getA(void) const;
void setA(const double& a);

double getB(void) const;
void setB(const double& b);

double getC(void) const;
void setC(const double& c);

I mean should getters be always const and setters take as argument reference to an object, rather than copy it, which would be probably a little bit slower?

Overpain
  • 161
  • 3
  • 7
  • 8
    If you class has getters and setters in amounts that this is an issue, I'd seriously [question its design](http://www.idinews.com/quasiClass.pdf). – sbi Nov 16 '10 at 14:30
  • 1
    I agree with @sbi to a point. As that article alludes, if you're using setters and getters for the sole purpose of accessing something private then it's silly. However, there's a situation that article doesn't touch on: when you have a legitimate need to treat the private data as being semi- or completely opaque (endianness, serializing/de-serializing to name a few), particularly if the type being represented wraps more than one piece of data. For example: http://codereview.stackexchange.com/questions/7786/c-like-class-properties – Brian Vandenberg Sep 18 '15 at 15:47
  • Also, since the author of that article doesn't spell it out (it's only briefly mentioned near the end), I want to emphasize something from the article: `3. A lack of essential operators and other methods forces user programs to manipulate the object through the get and set accessor functions.` If your accessors are operators, this at least implies the author of that article wouldn't [necessarily] have the same complaint. – Brian Vandenberg Sep 18 '15 at 15:53
  • @Brian: Well, the OP has silly getters and asks _Is it good coding style?_ That's a very reliable sign for a newbie straying from the _Path of Truth(™)_, rather than someone asking about abstracting away some implementation details behind getters. – sbi Sep 20 '15 at 19:51

6 Answers6

4

Haro to the naysayers!

Boost.Fusion.Map is what you're looking for as a basis.

namespace result_of = boost::fusion::result_of;

class MyClass
{
public:
  struct AType {};
  struct BType {};
  struct CType {};

  template <typename Type>
  typename result_of::at< DataType, Type >::type &
  access(Type) { return boost::fusion::at<Type>(mData); }

  template <typename Type>
  typename result_of::at< DataType, Type >::type const &
  get(Type) const { return boost::fusion::at<Type>(mData); }

  template <typename Type>
  void set(Type, typename result_of::at< DataType, Type >::type const & v)
  {
    boost::fusion::at<Type>(mData) = v;
  }

private:
  typedef boost::fusion::map <
    std::pair<AType, int>,
    std::pair<BType, std::string>,
    std::pair<CType, float> > DataType;
  DataType mData;
};
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 2
    And then how easy is it to specialize one of those methods to do something different? (Because if you're not going to do that, you might as well just have public data members.) – aschepler Nov 16 '10 at 18:54
  • @Brian Vandenberg: Sorry that your edit got rejected; I adjusted the code. – Matthieu M. Sep 18 '15 at 06:23
2

design your programs in a way, that there is less need for getters and setters. You could create them by a macro or implement some kind of propertysyntax(which is possible but there are always things that don't work right).. However, I suppose just writing the accessors when they are needed or generate them with your IDE is the best and most usual way.

As for your second question, you should use it at least for object type, you don't really need it for primitives. Personally I don't use it either if I need a copy of the object anyway, however others may claim that it might be better to do this explicit.

DaVinci
  • 1,391
  • 2
  • 12
  • 27
  • 1
    "design your programs in a way, that there is less need for getters and setters" It's against the incapsulation rule of Object Oriented Programming... – peoro Nov 16 '10 at 14:39
  • @peoro: I did not say that he should replace the accessors by public members. He should simply operate on his data by using more meaningful functions. If there are so many accessors which do nothing else but returning and setting the internal variable it's very probable, that the classes are used very similiar to POD structures and thus only seemingly encapsulated. – DaVinci Nov 16 '10 at 14:46
  • @peoro: you might also take a look at sbis link. – DaVinci Nov 16 '10 at 14:48
  • Ok, I understood your original post as "don't have setters and getters". What's sbis link? – peoro Nov 16 '10 at 14:54
  • I was missing an apostrophe. sbi commented on the question posting this [link](http://www.idinews.com/quasiClass.pdf) – DaVinci Nov 16 '10 at 15:09
  • +1, excellent link and the need to reduce getters/setters is very real. – Moo-Juice Nov 16 '10 at 15:14
  • @peoro: Disagree. Providing a public data member doesn't break encapsulation any more than providing public getters and setters that do nothing that the public data member would not do. – John Dibling Nov 16 '10 at 15:47
  • @John: it does, it hides the implementation details of WHERE is the data member stored. You can have it barebone in your class, then change it to another class that will be composed, or allocate it dynamically... none of which is possible with a public data member. – Matthieu M. Nov 16 '10 at 15:52
  • @Matthieu: I get what your'e saying, but I still disagree that *conceptually* getters & setters provide better encapsulation. In order for getters & setters to provide *true* encapsulation, the entire interface would have to be an abstract base class. Else the implementation details are just hanging out there, for everyone to see. – John Dibling Nov 16 '10 at 15:58
  • @MatthieuM. Then use a `typedef`. Creating an opaque type solely because you might need to change the underlying implementation is a form of false laziness: http://c2.com/cgi/wiki?FalseLaziness – Brian Vandenberg Sep 18 '15 at 16:11
  • @BrianVandenberg: I have no idea how your comment relates to this *5 years old* conversation; I may have forgotten some concepts, so if you really hope for an answer, I am afraid I'll need you to extrapolate what you are talking about. – Matthieu M. Sep 18 '15 at 17:01
  • @MatthieuM. Unless I read what you wrote incorrectly, I took your last statement to mean "make it opaque initially because down the road you may want to change the underlying behavior" (eg, having it dynamically allocated). If I read that wrong, disregard what I said. – Brian Vandenberg Sep 18 '15 at 21:29
  • @BrianVandenberg: I was talking about hiding the implementation details (how the data is represented inside the class) and thus indeed recommended making it opaque so as to be able to change how said data is represented; normally this should not affect the behavior or public API. I would disagree this is false laziness in general; on the other hand, I only recommend this when the API is publicly consumed, hiding implementation details internally is not worth the headache. – Matthieu M. Sep 19 '15 at 12:16
0

I can't see a way for templating to directly help you compactify your getter/setter pairs unless you want to wrap your members inside templated accessor classes like this. Another possibility is using a #define macro to emulate C# properties (if macros don't scare you or anyone reading your code).

Whether your getters return (const) references to members, return pointers to members, or copy them depends on a few factors. You have to consider whether it's expensive to copy them (performance wise), whether it semantically makes sense to copy them, and whether it should be possible for the information you're returning to outlive the class you're getting it from (if you return a pointer/reference to a member, it will be left dangling as soon as you delete your object). And I'd use pointers over references if you want to allow for the possibility of the member being null.

For getters, I tend to return const references for anything but primitives, which I copy. For setters, it's conventional to have a const reference parameter.

asdfjklqwer
  • 3,536
  • 21
  • 19
0

It's technically possible to create a single exmlClass::set<PMF> function template such that exmlClass::set<&exmlClass::a_> is valid. However, what would be the point?

MSalters
  • 173,980
  • 10
  • 155
  • 350
-1

In theory, you could:

template<typename A, typename B, typename C>
class Object
{
private:
    A _a;
    B _b;
    C _c;

public:
    Object()
    {
    };  // eo ctor

    // properties

    A getA() const {return(_a);}
    void setA(const A& _val) {_a = _val;}

    // etc for B & C
}; // eo class Object

    // .....

    Object<int, double, char> myObject;

There are several problems I see with this. Firstly is that getters/setters shouldn't be "abstract" in what they convey to the users of your class. What are you going to call this getters/setters? getA() ? getAValue()? What does that even mean?

Secondly, this defines 3. How many do you need for your objects? 1, 2, 4, 9?

Thirdly, Getters/setters should be named appropriately to their function:

getName()
getAddress()
getMovie()

It sounds like you just want to save on typing, never an excuse to complicate your design imho.

With regards to your 2nd point, return reference to objects (const, preferably) but don't bother with small, integral POD (Plain-Old-Data) types such as int, char, bool etcteras.

Moo-Juice
  • 38,257
  • 10
  • 78
  • 128
-1

No, you cannot define any sort of template that can create functions or function-like things with an unbounded set of names like getA, getB, ....

A macro could do it, but that's an even worse idea.

I typically pass/return a class object by const reference, but simple built-in types like double just by value:

public:
  const ClassType& getObj() const;
  void setObj(const ClassType& obj);
  double getNum() const;
  void setNum(double num);
aschepler
  • 70,891
  • 9
  • 107
  • 161