如何制作一个好的set / get方法

时间:2014-11-11 07:41:00

标签: c++

例如,我们有这个类:

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

在这7种方法中,我们可以设置并获得坐标的x,y和z。我感兴趣的是创建更少的方法set()get(),我可以在其中调用类似的东西:

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 */
}

8 个答案:

答案 0 :(得分:6)

如果Coord类很简单,那么它也可以是struct

无论如何,你可以这样写:

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

并以这种方式使用该类:

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 */

答案 1 :(得分:1)

getter和setter旨在保护您的数据并提供封装。

例如,它们允许您为获取和设置操作添加副作用(例如写入日志),或者允许您在以后引发可怕问题之前尽早捕获无效值(例如,防止设置大于n的值) )。

这是一个简短而有人工作的二传器例子:

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

假设您的c.set.x(5)示例未使用某些糟糕的预处理器宏,则需要Coord类具有名为set的成员变量及方法

x()
y()
z()

这需要与在set_x()类中编写set_y()set_z()Coord方法一样多的代码,但这些方法不属于类Coord ,而是属于另一个本身用作Coord成员变量的类。这样做实际上没有任何逻辑意义...... x,y和z值属于Coord,对它们的操作是Coord上的操作。

此外,方法x() y()z()将不再遵循制作方法动词的一般原则。任何用这些方法阅读课程的人都不知道z()应该做什么功能!

它还会造成重构的噩梦:例如,如果将来出现业务要求,这意味着没有Coords可以拥有大于21的x值,维持您的代码将不得不更改作为Coord成员的类而不是Coord类本身。

使用getter和setter方法进行封装通常是一个非常好的主意,在C ++中,内联的好处甚至可以不增加运行时开销。但要坚持“让一切尽可能简单但不简单”的原则。换句话说,get_x()和set_x()被广泛理解,有用,易于重构,方便,自我记录和高效......其他方法可能不那么容易。

答案 2 :(得分:0)

首先:您对c.set.x的使用不起作用,因为您会在对象set上调用公共元素c,其中set具有公共元素{{1 }}

我发现这两个课程都缺乏干净的代码标准和通常的getter和setter风格 - 即使没有指定任何语言。

通常的方法是创建以下内容:

x

虽然有些人更喜欢使用m_x作为setter变量参数或任何其他约定。

无论如何,每个人都会直接理解你的代码。能够设置和获取x,y,z的坐标值,如果有人关注,它会看起来很标准 - 默认行为:

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

答案 3 :(得分:0)

你已经得到了一些很好的答案,但如果你真的想要一个具有较少的setter和getter的语法,你也可以使用枚举。客户端语法可能会变得有点笨拙和笨拙,但它当然取决于您正在寻找的内容!

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

答案 4 :(得分:0)

如果验证不是一个问题,那么公开它的或多或少的标准方法是从非const访问器返回可变引用,并从const one返回值。这允许您将接口与存储分开,而不会使语法过于繁重。

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

这将允许c.x()获取x坐标的值,无论Coord对象是否为const,并允许使用语法c.x() = value设置值。


为了完整性,您可以使用以下代码获得所需的语法,但我强烈建议不要使用它。这是一个额外的代码,没有真正的好处,并创建一个不常见的语法,大多数程序员不会发现它直观。

该技术创建了两个嵌套类getterssetters,并将它们的实例公开为Coord的公共成员。

这是作为如何实现您要求的结果的示例提供的,但我不建议采用这种方法。

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

答案 5 :(得分:0)

这个奇怪的代码正是你所要求的 - 只是C ++的乐趣。不要这样做!

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

输出:

0 0 0
1 2 3
5 6 7

答案 6 :(得分:0)

实际上可以根据您的要求减少功能,如下所示,

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

};

在打电话时你可以像下面这样打电话,

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

答案 7 :(得分:-1)

你无法完全按照自己的意愿行事。

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

c.set子表达式正在从set检索字段c(除非set#define - d宏,但这很愚蠢)。