C++ C++;自动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; } }; 模板

对于(几乎)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; }
};
模板
类属性
{
受保护的:
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函数传递

在其他一些语言中,getter和setter是防止实现细节逃逸到接口中的一种方法;直接公开字段后,如果不更改代码中访问该字段的所有站点,以后可能无法将其重新实现为属性(使用getter和setter函数)

在C++中,这不适用(如此强烈)。您可以将任何字段的类型更改为覆盖
运算符=
,并隐式转换为所需类型(对于“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
    }
}