如何制作一个好的设置/获取方法
How to make a good set/get method
例如,我们有这个类:
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 */
}
如果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 */
和 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
with 方法的成员变量
x()
y()
z()
这将需要与在Coord
类中编写set_x()
、set_y()
和set_z()
方法一样多的代码,但这些方法不属于类 Coord,而是属于另一个类,该类本身用作 Coord
的成员变量。这样做真的没有任何逻辑意义......x、y 和 z 值属于坐标,对它们的运算就是对坐标的运算。
此外,方法x()
y()
和z()
将不再遵循使方法动词的一般原则。任何使用这些方法阅读类的人都不知道函数 z(( 应该做什么!
它还会造成重构的噩梦:例如,如果将来出现一个业务需求,这意味着没有 Coords 的值可以大于 21 somone 维护您的代码将不得不更改作为 Coord 成员的类而不是 Coord 类本身。
使用 getter 和 setter 方法进行封装通常是一个非常好的主意,C++内联的好处甚至可以不增加运行时开销。但要坚持"让一切尽可能简单,但不要更简单"的原则。换句话说,get_x((和set_x((是广泛理解的,有用的,易于重构的,方便的,自我记录的和高性能的。其他方法可能不那么重要。
首先:您对c.set.x
的使用不起作用,因为您会在对象c
上调用公共元素set
,并且set
具有公共元素x
。
我发现这两个类都缺乏干净的代码标准和通常的getter和setter风格 - 即使没有指定任何语言。
一种常用的方法是创建以下内容:
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; }
};
尽管有些人更喜欢使用 m_x 作为 setter 变量参数或任何其他约定。
无论如何,每个人都会直接理解你的代码。能够设置和获取 x、y、z 的坐标值,如果有人执行以下操作,它看起来会非常标准的默认行为:
Coord P(10, 15, 20);
std::cout << P.getX() << " " << P.getY() << std::endl;
P.setX(-10);
P.setZ(40);
你已经得到了一些很好的答案,但如果你真的想要一个具有更少 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;
}
这个奇怪的代码完全按照你的要求去做 - 只是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
如果验证不是问题,则公开这一点或多或少的标准方法是从非 const 访问器返回可变引用,并从 const 访问器返回值。 这允许您将接口与存储分开,同时不会使语法太重。
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
设置值。
为了完整起见,您可以使用以下代码获得所需的语法,但我强烈建议不要这样做。 它是大量额外的代码,没有提供真正的好处,并且创建了一种不常见的语法,大多数程序员不会发现它直观。
该技术创建两个嵌套类getters
和setters
,并将它们的实例公开为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;
}
(演示(
实际上,该功能可以根据您的要求减少,如下所示,
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
你不能完全按照自己的意愿去做。
在
c.set.x(5); /* only set x */
c.set
子表达式是从c
中检索字段set
(除非set
是 #define
-D 宏,但那会很愚蠢(。
- 如何获取进程以设置其亲和力?
- 如何获取控制面板设置值,如字体大小
- 获取和设置函数 c++
- 适用于 macOS 的 Xcode 应用程序。这就是我设置从USB麦克风输入获取音频的方式。一年前工作,现在没有了。为什么
- 在 C++ 中将函数获取和设置为虚拟函数
- Qt 原子 int 获取并立即设置
- 提升获取文本的区域设置"Conversion failed"
- 如何使用C++获取/设置OBS中的垂直滚动过滤器属性?
- 在通过 P/Invoke 获取的 C++ 结构上设置 C# 回调
- 如何在Windows中获取和设置系统音量
- 如何设置获取类的私有成员:寻找更好的方法
- 在 c++ 中为我的类设置/获取方法时遇到问题
- 通过 C/C++ 使用 JPEG 像素格式在 v4l2 中设置/获取相机 JPEG 压缩质量
- C++字符串和设置/获取函数
- 如何制作一个好的设置/获取方法
- 设置获取指针
- 在c++中通过指针设置/获取值
- 设置/获取 Java 列表<>从 C 代码
- 在窗口模式下设置/获取我的绝对鼠标位置
- 使用复共轭来设置/获取数组值的代理