How to make a good set / get method

For example, we have this class:

class Coord
{
  double x;
  double y;
  double z;

public:
  Coord() { x = y = z = 0; }

  void set(double xx, double yy, double zz)
  {
    x = xx;
    y = yy;
    z = zz;
  }

  void set_x(double xx) { x = xx; }
  void set_y(double yy) { y = yy; }
  void set_z(double zz) { z = zz; }

  double get_x() { return x; }
  double get_y() { return y; }
  double get_z() { return z; }
};

      

With these 7 methods, we can set and get x, y and z coordinates. I am interested in creating fewer methods set()

and get()

where I can call something like this:

int main()
{
  Coord c;

  c.set.x(5); /* only set x */
  c.set.y(6); /* or y */
  c.set.z(7); /* or z */
  c.set(1,2,5); /* or setting x, y and z */

  c.get.x(); /* only get x */
  c.get.y(); /* or y */
  c.get.z(); /* or z */
}

      

+3


source to share


8 answers


If the class is Coord

that simple, it might as well struct

.

In any case, you can write something like:

class Coord
{
public:
  enum xyz {x = 0, y, z};

  Coord() : vec{x, y, z} {}

  template<xyz C> void set(double v) { vec[C] = v; }
  template<xyz C> double get() const { return vec[C]; }

  void set(double xx, double yy, double zz)
  {
    set<Coord::x>(xx);
    set<Coord::y>(yy);
    set<Coord::z>(zz);
  }

private:
  double vec[z + 1];
};

      



and use the class like this:

Coord c;

c.set<Coord::x>(5); /* only set x */
c.set<Coord::y>(6); /* or y */
c.set<Coord::z>(7); /* or z */
c.set(1,2,5); /* or setting x, y and z */

c.get<Coord::x>(); /* only get x */
c.get<Coord::y>(); /* or y */
c.get<Coord::z>(); /* or z */

      

+6


source


getters and setters are designed to protect your data and provide encapsulation.

For example, they allow you to add side effects to get and set operations (for example, write to the log), or allow you to catch invalid values ​​sooner rather than later, they cause dire problems (for example, preventing values ​​greater than n from exceeding).

Here's an example of a short and contrived setter:

void set_x(int x)
{
    // prevent an invalid value for x
    if( x > 11 ) x = 11;

    // set x
    this.x = x;

    // log the operation
    log("user set x to {0}", x);    
}

      

Assuming your example c.set.x(5)

doesn't use some monstrous preprocessor macros, it would require the Coord class to have a member variable called set

with methods



x()
y()
z()

      

This will require the same code as the recording methods set_x()

, set_y()

and set_z()

in your class Coord

, but the methods do not belong to the class Coord, and belong to another class, which itself is used as a member variable Coord

. It won't make any logical sense ... the x, y and z values ​​are relative to the coordinate, and operations on them are operations on the coordinate.

In addition, x()

y()

and methods z()

will no longer obey the general principle of creating verb methods. Anyone who reads the class using these methods has no idea what function z () is supposed to serve!

It would also create a refactoring nightmare: if, for example, there was a business requirement in the future that meant that none of the coords could ever have x values ​​greater than 21, then maintaining your code would have to change the member class The coordinator, not the class itself.

Encapsulation with getter and setter methods is often a really good idea, and in C ++, with the benefit of encrustation, it can't even create unnecessary work. But stick to the principle "Keep it as simple as possible, but not simpler." In other words, get_x () and set_x () are widely understood, useful, easily refactored, convenient, self-documenting, and efficient ... other approaches are likely to be less like that.

+1


source


First: using c.set.x

will not work because you are calling a public object set

on your object c

and where set

has an open element x

.

I believe there is a lack of clean code standards and the usual getter and setter style for both classes - even without specifying the language.

The usual way would be to create the following:

class Coord
{
  double x;
  double y;
  double z;

public:

  Coord() { 
    x = 0;
    y = 0;
    z = 0; 
  }

  Coord(double x, double y, double z)
  {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  void setX(double x) { this.x = x; }
  void setY(double y) { this.y = y; }
  void setZ(double z) { this.z = z; }

  double getX() { return x; }
  double getY() { return y; }
  double getZ() { return z; }
};

      

Although some people prefer to use m_x as a parameter to a setter variable or any other convention.

In any case, everyone will understand your code directly. Can set and get coordinate values ​​for x, y, z, and it would look pretty standard - by default if someone does the following:

Coord P(10, 15, 20);
std::cout << P.getX() << " " << P.getY() << std::endl;
P.setX(-10);
P.setZ(40);

      

0


source


You already have some good answers, but you can also use enumeration if you really want a syntax with fewer setters and getters. The client syntax can get a little awkward and awkward, but of course it depends on what you are looking for!

#include <iostream>

class Coord {
public:

    enum Axis {
        X = 0,
        Y,
        Z,
        NUM_AXES
    };

    // Using extended initializer lists (C++11)
    Coord() : axes_{0, 0, 0} {}
    Coord(double x, double y, double z) : axes_{x, y, z} {}

    void set(Axis a, double d) {
        axes_[a] = d;
    }
    double get(Axis a) const {
        return axes_[a];
    }

private:
    double axes_[NUM_AXES];

    // Copy constructor and assgn. operator included for good measure
    Coord(const Coord &);
    void operator=(const Coord &);  
};

int main()
{
    Coord c(1, 2, 3);
    std::cout << "X: " << c.get(Coord::X) << std::endl;
    std::cout << "Y: " << c.get(Coord::Y) << std::endl;
    std::cout << "Z: " << c.get(Coord::Z) << std::endl;
    c.set(Coord::Y, 4);
    std::cout << "Y: " << c.get(Coord::Y) << std::endl;
    return 0;
}

      

0


source


The more or less standard way to expose this, if validation is not a problem, is to return mutable references from non-const access and values ​​from const. This allows you to decouple the interface from the store without doing too much syntax.

private:
    double m_x, m_y, m_z;

public:
    double & x() { return m_x; }
    double & y() { return m_y; }
    double & z() { return m_z; }

    double x() const { return m_x; }
    double y() const { return m_y; }
    double z() const { return m_z; }

      

This will c.x()

get the x coordinate value, whether the object is Coord

const or not, and allows you to set the value using syntax c.x() = value

.


In the interest of completeness, you can get exactly the syntax you want using the following code, but I would highly recommend against it. This is a lot of extra code, has no real benefit, and creates a syntax that is unusual and most programmers won't find intuitive.

The method creates two nested classes getters

and setters

and exposes them as public members Coord

.

This is presented as an example of how to achieve the result you asked, but I do not recommend this approach.

class Coord
{
private:
    double x, y, z;

public:
    Coord();
    Coord(double, double, double);

    class setters {
        friend class Coord;

    private:
        explicit setters(Coord &);

    public:
        setters(setters const &) = delete;
        setters & operator=(setters const &) = delete;

        void x(double) const;
        void y(double) const;
        void z(double) const;

    private:
        Coord & coord;
    };
    friend class setters;

    class getters {
        friend class Coord;

    private:
        explicit getters(Coord const &);

    public:
        getters(getters const &) = delete;
        getters & operator=(getters const &) = delete;

        double x() const;
        double y() const;
        double z() const;

    private:
        Coord const & coord;
    };
    friend class getters;

    setters const set;
    getters const get;
};

Coord::Coord() : x(0), y(0), z(0), set(*this), get(*this) { }

Coord::Coord(double px, double py, double pz) : x(px), y(py), z(pz), set(*this), get(*this) { }

Coord::setters::setters(Coord & c) : coord(c) { }

void Coord::setters::x(double px) const {
    coord.x = px;
}

void Coord::setters::y(double py) const {
    coord.y = py;
}

void Coord::setters::z(double pz) const {
    coord.z = pz;
}

Coord::getters::getters(Coord const & c) : coord(c) { }

double Coord::getters::x() const {
    return coord.x;
}

double Coord::getters::y() const {
    return coord.y;
}

double Coord::getters::z() const {
    return coord.z;
}

      

( Demo )

0


source


This weird code does exactly what you ask - it's just C ++ fun. Do not do that!

#include <iostream>
using namespace std;

class Coord {
    double x;
    double y;
    double z;

public:
    class Setter {
    public:
        Setter(Coord& coord) : c(coord) {}
        void x(double value) { c.x = value; }
        void y(double value) { c.y = value; }
        void z(double value) { c.z = value; }
        void operator()(double x, double y, double z) { c.x = x; c.y = y; c.z = z; }
    private:
        Coord& c;
    };

    class Getter {
    public:
        Getter(Coord& coord) : c(coord) {}
        double x() { return c.x; }
        double y() { return c.y; }
        double z() { return c.z; }

    private:
        Coord& c;
    };

    Setter set;
    Getter get;

    Coord() :  set(*this), get(*this) { x = y = z = 0;  }

    friend class Setter;
};

int main()
{
    Coord c;

    cout << c.get.x() << " " << c.get.y() << " " << c.get.z() << endl;

    c.set.x(1);
    c.set.y(2);
    c.set.z(3);

    cout << c.get.x() << " " << c.get.y() << " " << c.get.z() << endl;

    c.set(5, 6, 7);

    cout << c.get.x() << " " << c.get.y() << " " << c.get.z() << endl;

    return 0;
}

      

Output:

0 0 0
1 2 3
5 6 7

      

0


source


Actually the function can be scaled down according to your requirement like this:

class Coord
{
     double x;
     double y;
     double z;

   public:

      Coord() { 
            x = 0;
            y = 0;
            z = 0; 
      }

      void GetValues(double* x=NULL, double* y=NULL, double* z=NULL);
      void SetValues(double x=0, double y=0, double z=0)

      /* You can use constructors like below to set value at the creation of object*/
      Coord(double x, double y, double z)
      {
         this.x = x;
         this.y = y;
         this.z = z;
      }

     /*You can set the values of x, y & z in a single function as follows. It can be used at any time without restriction */
      void SetValues(double x, double y, double z)
      {
         if(x > 0) //It is optional to use condition so that you can update any one variable aloen by sending other two as ZERO
         {
            this.x = x;
         }
         if(y > 0)
         {
            this.y = y;
         }
         if(z > 0)
         {
            this.z = z;
         }
      }

      /*You can Get the values of x, y & z in a single function as follows. Pass By Reference id the concept you need */
      void GetValues(double* x, double* y, double* z)
      {
         if(x != NULL) //It x is not null. 
         {
            x = this.x;
         }
         if(y != NULL)
         {
            y = this.y;
         }
         if(z != NULL)
         {
            z= this.z;
         }
      }

      

};

when called, you can call like this:

SetValues(10, 20, 0); //To set x and y values alone.
double x1 = 0;double y1 = 0;double z1 = 0;
GetValues(&x1, &y1, &z1)//It will return the values x1 y1 and z1 as 10, 20 & 0

      

0


source


You cannot do exactly what you want.

IN

c.set.x(5); /* only set x */

      

the subexpression c.set

extracts a field set

from c

(unless set

it is a #define

-d macro , but that would be silly).

-1


source







All Articles