“Forward-unbreakable”访问器类模板 [C++]

2024-02-26

除非我完全弄错了,否则 getter/setter 模式是用于两件事的常见模式:

  1. 创建一个私有变量,以便可以使用它,但永远不会修改它,只需提供一个getVariable方法(或者,更罕见的是,只能通过仅提供一个setVariable方法)。
  2. 为了确保将来,如果您碰巧遇到一个问题,一个好的解决方案就是在变量进入和/或离开类之前简单地对其进行处理,那么您可以使用实际的实现来处理该变量在 getter 和 setter 方法上,而不是简单地返回或设置值。这样,更改就不会传播到代码的其余部分。

问题#1:我是否遗漏了访问器的任何使用,或者我的任何假设是否不正确?我不确定我的观点是否正确。

问题#2:是否有任何类型的模板优点可以让我不必为我的成员变量编写访问器?我没有找到。

问题 #3:以下类模板是否是实现 getter 而无需实际编写访问器的好方法?

template <class T>
struct TemplateParameterIndirection // This hack works for MinGW's GCC 4.4.1, dunno others
{
    typedef T Type;
};

template <typename T,class Owner>
class Getter
{
public:
    friend class TemplateParameterIndirection<Owner>::Type; // Befriends template parameter

    template <typename ... Args>
    Getter(Args args) : value(args ...) {} // Uses C++0x

    T get() { return value; }

protected:
    T value;
};

class Window
{
public:
    Getter<uint32_t,Window> width;
    Getter<uint32_t,Window> height;

    void resize(uint32_t width,uint32_t height)
    {
        // do actual window resizing logic

        width.value = width; // access permitted: Getter befriends Window
        height.value = height; // same here
    }
};

void someExternalFunction()
{
    Window win;

    win.resize(640,480); // Ok: public method

    // This works: Getter::get() is public
    std::cout << "Current window size: " << win.width.get() << 'x' << win.height.get() << ".\n";

    // This doesn't work: Getter::value is private
    win.width.value = 640;
    win.height.value = 480;
}

这对我来说看起来很公平,我什至可以重新实现get通过使用其他一些部分模板专业化技巧来实现逻辑。同样的情况也适用于某种 Setter 甚至 GetterSetter 类模板。

你怎么看?


虽然从实施的角度来看,该解决方案很简洁,但从架构上来说,它只完成了一半。 Getter/Setter 模式的要点是让类控制其数据并减少耦合(即其他类知道how数据被存储)。该解决方案实现了前者,但不能完全实现后者。

事实上,另一个类现在必须知道两件事 - 变量的名称和 getter 上的方法(即.get()) 而不是一个 - 例如getWidth()。这会导致耦合增加。

话虽如此,这却是众所周知的建筑问题。归根结底,这并不重要。

EDIT好吧,现在废话了,这里是使用运算符的 getter 版本,所以你不必这样做.value or .get()

template <class T>
struct TemplateParameterIndirection // This hack works for MinGW's GCC 4.4.1, dunno others
{
    typedef T Type;
};

template <typename T,class Owner>
class Getter
{
public:
    friend TemplateParameterIndirection<Owner>::Type; // Befriends template parameter

    operator T()
    {
        return value;
    }

protected:
    T value;

    T& operator=( T other )
    {
       value = other;
       return value;  
    }


};

class Window
{
public:
    Getter<int,Window> _width;
    Getter<int,Window> _height;

    void resize(int width,int height)
    {
        // do actual window resizing logic
        _width = width; //using the operator
        _height = height; //using the operator
    }
};

void someExternalFunction()
{
    Window win;

    win.resize(640,480); // Ok: public method
    int w2 = win._width; //using the operator
    //win._height = 480; //KABOOM
}

EDIT修复了硬编码赋值运算符。如果类型本身有赋值运算符,这应该可以很好地工作。默认情况下,结构体具有这些结构,因此对于简单的结构体来说,它应该可以开箱即用。

对于更复杂的类,您将需要实现一个足够公平的赋值运算符。和RVO http://en.wikipedia.org/wiki/Return_value_optimization and 写时复制 http://en.wikipedia.org/wiki/Copy-on-write优化,这在运行时应该相当有效。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

“Forward-unbreakable”访问器类模板 [C++] 的相关文章

随机推荐