开发者

Templates for setters and getters

开发者 https://www.devze.com 2023-01-25 21:56 出处:网络
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:

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?


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


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.


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.


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?


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);


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号