6

考虑以下类:

class MyClass1
{
    public:
        double x() const {return _x;} // getter
        double y() const {return _y;} // getter
        double z() const {return _x*_y;} // getter
        void x(const double var) {_x = var;} // setter
        void y(const double var) {_y = var;} // setter
        void z(const double var) {_x = var; _y = 1;} // setter
    protected:
        double _x;
        double _y;
};

由于 的实际内容MyClass1是一个实现细节,因此 getter 和 setter 提供了一种统一的方式来获取和设置类内容,即使它们是相互依赖的(这里_z不存在内部但对用户而言,z是一个变量,如xand y)。

现在为了避免必须为xand编写 getter/setter y,可以使用这样的包装器:

template <typename Type>
class Wrapper
{
    public:
        constexpr Wrapper(const Type& value) {_value = value;}
        constexpr Type& operator()() {return _value;}
        constexpr const Type& operator()() const {return _value;}
        constexpr void operator()(const Type& value) {_value = value;}
    protected:
        _value;
};

现在原来的类变成了:

class MyClass2
{
    public:
        Wrapper<double> x;
        Wrapper<double> y;
        double z() const {return x*y;} // getter
        void z(const double var) {x = var; y = 1;} // setter
};

避免编写 getter/setter 是一种危险的做法还是一个好的解决方案?

注意:这里MyClass1MyClass2只是例子。我的问题非常“笼统”:Wrapper当 getter/setter 只是返回/设置一个内部值时,用提议的方法替换类的 getter/setter 是否危险。

4

3 回答 3

1

正如您所提到的,getter 和 setter 的主要目的是提供一种统一的方式来访问和设置您的私有实例变量。

从您的包装器解决方案中,如果在程序生命周期的某个时候您决定更改设置器,您可以丢弃包装器并将其替换为 MyClass1 中的原始获取器/设置器 - 无需更改所有其他组件调用它的代码。

因此,从那时起,我认为您的解决方案是一种有效的方法,可以让您免于输入额外的几行代码。

于 2013-01-25T05:22:09.380 回答
1

我觉得那里没有什么特别危险的地方,但它似乎没有任何收获。C++ 为任何类型的对象提供引用语义,这与 setter 函数不兼容。有时实际的内容不仅仅是一个细节。

您也可以采用其他方式(实际上,这是我单击此问题时所期望看到的):

struct virt_z {
    double x;
    double y;
    struct z_wrap {
        virt_z &parent;

        operator double() { return parent.x * parent.y; }
        z_wrap &operator=( double in ) {
            parent.x = in;
            parent.y = 1;
            return *this;
        }
        z_wrap( virt_z &in ) : parent( in ) {}
    } z;

    virt_z() : z( *this ) {}
    virt_z( virt_z const &o ) : x( o.x ), y( o.y ), z( *this ) {}
};

https://ideone.com/qqgj3D

于 2013-01-25T05:24:35.123 回答
1

它本身并不危险,只是更难使用(对于类用户)。MyClass2 混淆了界面。

它可能会让您编写代码变得不那么乏味,但您只需编写一次代码 - 接口将被多次重用。因此应该优先使用读码器。

由于这个原因,MyClass1 优于 MyClass2 和 Potatoswatter 解决方案。

(即使 C++ 中有一种方法可以做到这一点:

class MyClass3
{
    double x, y, z;
}

MyClass3::z::operator=(double) { ... } // property set
double MyClass3::z::operator() { ... } // property get

就像在 C# 中一样,我认为这仍然是一个坏主意,因为这种“隐藏”代码会导致错误的假设,从而减慢调试速度。函数样式至少让您认为可能有比原始副本更复杂的事情发生。)

于 2013-01-25T07:19:23.060 回答