C++ C++;自动getter setter方法的类模板-好/坏实践?
对于(几乎)POD类中的属性,使用带有隐式getter和setter的模板类对象是一种好的做法吗 考虑以下模板示例:C++ C++;自动getter setter方法的类模板-好/坏实践?,c++,templates,getter-setter,C++,Templates,Getter Setter,对于(几乎)POD类中的属性,使用带有隐式getter和setter的模板类对象是一种好的做法吗 考虑以下模板示例: template<typename T> class Attribute { protected: T m_val; public: T * getAddress() { return &m_val; } T get() { return m_val; } void set(T v) { m_val = v; } }; 模板
template<typename T>
class Attribute
{
protected:
T m_val;
public:
T * getAddress() { return &m_val; }
T get() { return m_val; }
void set(T v) { m_val = v; }
};
模板
类属性
{
受保护的:
T m_val;
公众:
T*getAddress(){return&m_val;}
T get(){return m_val;}
无效集(tv){m_val=v;}
};
及其用法:
class A
{
public:
Attribute<float> floatAttr;
Attribute<int> intAttr;
Attribute<long> longAttr;
};
A类
{
公众:
属性floattr;
属性intAttr;
属性longAttr;
};
这样就可以封装数据,但实现开销更小
这种做法是好是坏(为什么)
编辑:陈述我从中看到的优点。不需要手动实现每个getter setter函数,但这些函数仍然具有通常的优点:
- 数据被封装,客户机需要使用getter setter函数,以后仍然可以以不同的方式实现这些函数李>
- 内部用法仍然是隐藏的,可以更改
- Getter和Setter函数可以作为lambda函数传递
运算符=
,并隐式转换为所需类型(对于“get”端)的类。(当然,有些用法不适用,例如,如果在客户端代码中创建了一个指针或引用,尽管我个人会避免这样做,并认为这是一个可疑的实践)。
也可以,因为C++是静态类型的,如果需要用适当的调用将字段和相应的访问转换成一个GET/SETER对,工具(IDE等)也更容易提供自动重构。 根据证据,这里是对您的
属性
模板的修改,该模板允许您的“属性”充当直接暴露字段的角色(除了&
将返回属性的地址而不是隐藏字段):
。。。但是,这样做很大程度上破坏了封装(在这一点上,您可能会考虑将代码的返回类型>运算符=< /代码>改为<代码> t>代码>或<代码>空白>代码>出于同样的原因)。
如果最初直接公开该字段,则可以使用上述模板的实例替换其定义,并且大多数使用不会受到影响。这说明为什么在C++中,吸收器/设置器模式并不总是必要的。
您自己的解决方案虽然封装了getter/setter函数后面的原始字段,但实际上还公开了另一个字段:属性
成员(floatAttr
等)。要使其作为一种封装方法发挥作用,您需要依赖于不知道(或不关心)属性字段本身类型的用户;也就是说,你认为没有人会:
A a;
Attribute<float> & float_attr = a.floatAttr;
。。。所以在这个意义上,你实现了一些封装;真正的问题是有更好的方法来做到这一点
最后,值得一提的是,您建议的属性
模板以及我在上面展示的备选方案都将字段移动到一个类中(属性
,对于某些T),该类与原始父类(a
)分离。如果要改变执行情况,现在在某种程度上受到这一事实的限制;属性对象自然没有对包含它的对象的引用。例如,假设我有一个类B
,它有一个属性level
:
class B {
public:
Attribute<int> level;
};
class B {
public:
Attribute<int> level;
Attribute<int> min_level;
};
此外,假设我现在想要在赋值时将level
约束为minu level
的值。这并不简单!虽然我可以使用自定义实现为level
提供一个新类型,但它将无法从包含的对象访问minu level
值:
class LevelAttribute {
int m_val;
public:
T &operator=(const T &a) {
m_val = std::max(min_level, a); // error - min_level not defined
}
}
要使其工作,需要将包含的对象传递到
LevelAttribute
对象中,这意味着存储一个额外的指针。典型的老式setter(直接在保存字段的类中声明为函数)可以避免此问题。与原始属性相比,此属性有哪些优点?getter和setter是一种反函数-pattern@Helion如果您只需要直接/简单的getter和setter,那么您可能不需要它们,只需将成员变量公开。像这样既有setter又有getter似乎是多余的。只需让用户直接(公开)访问即可。通常,设定器可以执行范围检查或其他输入验证。在这种情况下,setter和getter都可以
class B {
public:
Attribute<int> level;
};
class B {
public:
Attribute<int> level;
Attribute<int> min_level;
};
class LevelAttribute {
int m_val;
public:
T &operator=(const T &a) {
m_val = std::max(min_level, a); // error - min_level not defined
}
}