4

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

On these 7 methods we can set and get x,y and z of a coordinate. I am interested in create less methods set() and get() where I can call something like that:

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 */
}
Trytio
  • 108
  • 2
  • 11
marquesm91
  • 535
  • 6
  • 23
  • 3
    Please don't do that! – Karoly Horvath Nov 11 '14 at 07:43
  • @KarolyHorvath Why? Do you think my actual class is better? – marquesm91 Nov 11 '14 at 07:45
  • 1
    @KarolyHorvath can you please provide why not doing those things? – sfrehse Nov 11 '14 at 07:45
  • 1
    I believe the most standard usage of getter and setter methods are to do something `getMyPropertyName(void)` where myPropertyName is `x` in your case. If you follow camel-casing of class/object naming - then you should be using getX(), getY(), setX(), setY() - unless your organisation has come up with a define standard of writing C++ software with classes and objects? – ha9u63a7 Nov 11 '14 at 07:51
  • If you need both and get for something as simple as a coordinate, and you do not seem to care about limits, forget about getters and setters all together and make x, y and z public members – stijn Nov 11 '14 at 08:02
  • @hagubear I will maintain what I'm using - getX(), getY() ... - I am just curious if c++ can do what I ask! – marquesm91 Nov 11 '14 at 08:05
  • @marquesm91 The short answer is that yes, it can do that. But you shouldn't. – cdhowie Nov 11 '14 at 08:10
  • @cdhowie , I really like manlio answer! I think is the best approach of what I wanted – marquesm91 Nov 11 '14 at 08:17
  • @marquesm91 FWIW I updated my answer with an example of how you can get exactly the syntax you requested (`a.get.x()` and `a.set.x(value)`), though I can't stress strongly enough that I don't recommend doing this. It's only so you can see an example of how you might do this. – cdhowie Nov 11 '14 at 08:21
  • @cdhowie I am reading your answer now! Although this is not a good way, now I know is it possible to do! Thank you! – marquesm91 Nov 11 '14 at 08:30

8 Answers8

7

If the Coord class is that simple, it could also be a struct.

Anyway 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 this way:

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 */
manlio
  • 18,345
  • 14
  • 76
  • 126
  • It would be a good idea to pass the parameter in the setter function as a const reference. So instead of: **void set(double v)**, you could use: **void set(const double &v)**. In this case, it won't matter much, but if you were passing class objects, you would save on the creation of temporary objects. – Vishal Gupta Nov 11 '14 at 09:20
  • Built-in types (`char`, `int`, `double`...) and small objects (such as STL iterators) should normally be passed by value. For further details see http://stackoverflow.com/questions/270408/is-it-better-in-c-to-pass-by-value-or-pass-by-constant-reference – manlio Nov 11 '14 at 14:28
1

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

For example they allow you to add side effects to getting and setting operations (such as writing to a log), or allow you to catch invalid values early before they cause horrible problems later (For example preventing values greater than n being set).

Here's a brief and contrived setter example:

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 c.set.x(5) example is not using some whacky preprocessor macros, it would require that the Coord class have a member variable called set with methods

x()
y()
z()

This would require just as much code as writing a set_x(), set_y() and set_z() method in your Coord class, but the methods would not belong to the class Coord, instead belonging to another class that is itself used as a member variable of Coord. Doing so would not really make any logical sense... the x, y, and z values belong to Coord and operations on them are operations on the Coord.

Furthermore the methods x() y() and z() would no longer obey the general principle of making methods verbs. Anyone reading the class with those methods would have no idea what function z() is supposed to do!

It would also create a refactoring nightmare: If for example in the future a business requirement appeared that meant no Coords could ever have values of x greater than 21 somone maintaining your code would have to change a class that is a member of Coord rather than the Coord class itself.

Encapsulation with getter and setter methods is often a really good idea and in C++ with the benefit of inlining it can even add no runtime overhead. But keep to the principle "Make everything 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 performant... other approaches are likely to be less so.

Matt Coubrough
  • 3,739
  • 2
  • 26
  • 40
0

First: Your usage of c.set.x would not work because you would call a public element set on your object c and where set has a public element x.

I find both classes lack standards of clean code and usual style of getter and setter - even without specifying any language.

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

Though some prefer to use m_x as setter variable parameter or any other convention.

Anyhow everyone would directly understand your code. Is able to set and get coordinate values for x, y, z and it would look pretty standard-default-behaviour if someone does following:

Coord P(10, 15, 20);
std::cout << P.getX() << " " << P.getY() << std::endl;
P.setX(-10);
P.setZ(40);
Stefan
  • 2,603
  • 2
  • 33
  • 62
0

You've already gotten some good answers, but you could also use an enum if you really want a syntax with fewer setters and getters. The client syntax can get a little clunky and awkward, but it of course depends on what you're 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;
}
Victor Sand
  • 2,270
  • 1
  • 14
  • 32
0

The more or less standard way to expose this, if validation is not a concern, is to return mutable references from the non-const accessor, and values from the const one. This allows you to separate the interface from storage, while not making the syntax too heavy.

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 allow c.x() to obtain the value of the x coordinate whether the Coord object is const or not, and allows setting the value using the syntax c.x() = value.


In the interest of completeness, you can get exactly the syntax you want using the following code, but I would strongly recommend against it. It is a lot of extra code, provides no real benefit, and creates a syntax that is uncommon and most programmers will not find it intuitive.

The technique creates two nested classes getters and setters and exposes instances of them as public members of Coord.

This is provided as an example of how to achieve the result you asked for, 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)

cdhowie
  • 158,093
  • 24
  • 286
  • 300
0

This strange code does exactly what you ask - just C++ fun. Don't do this!

#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
Alex F
  • 42,307
  • 41
  • 144
  • 212
  • `set` and `get` should be declared `const` or you could do `Coord a, b; a.get = b.get;` etc. – cdhowie Nov 11 '14 at 08:22
  • My comment to this code is `Don't do this!` I don't even try to make it 100% correct and perfect, just code that makes OP syntax possible. – Alex F Nov 11 '14 at 08:24
0

Actually the function can be reduce based on your requirement as follows,

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

};

while calling you can call like the following,

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
Sridhar DD
  • 1,972
  • 1
  • 10
  • 17
-1

You cannot do exactly what you want.

In

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

the c.set subexpression is retrieving a field set from c (unless set is a #define-d macro, but that would be silly).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547