如何避免编写样板访问器代码

How to avoid having to write boilerplate accessor code

本文关键字:访问 代码 何避免      更新时间:2023-10-16

我发现,在编码C++代码时,我花了很多时间编写访问器样板代码,例如:

class A
{
  int x;
public:
  auto x();
  void set_x(decltype(x));
};

实现访问器的整个想法围绕着能够拦截对它们的读取和写入访问。我偶然发现了这个库(我不是作者)。这真的让我想知道,为了避免编写样板代码,是否可以/应该写这样的东西:

class A
{
public:
  property<int> x;
  A() {
    x.setter([this](int){ /* setter code */ });
  }
};

我的问题是:有哪些技术可以避免为getter和setter编写大量样板代码?

这里和那里有一些关于getter和setter是否是邪恶的讨论。

因此,我避免样板代码的策略是:尽量避免getter和setter。当需要一些纯数据类时,我将(少数)字段声明为公共字段。但是在这些情况下,我尽量避免给他们任何其他逻辑,我尽量保持这些类

另外,阅读关于告诉不要问的信息,例如来自马丁·福勒。

我猜你正在寻找这样的东西:

template <typename T>
class Property{
    private:
    T val;
    std::function<void(T& v,const T& newV)> setFN = nullptr;
    public:
    void setter(decltype(setFN) newSetter){
        setFN = newSetter;
    }
    void set(const T& newVal){
        if(!setFN)
            val = newVal;
        else
            setFN(val,newVal);
    }
    T get(){
        return val;
    }
};

所以基本上是一个模板类,能够存储一个 setter 函数。如果存储了一个,则调用它,如果没有,则只使用一个operator=(当然,这需要由 T 定义)。

用法:

int main() {
    Property<int> x;
    x.set(5);
    std::cout << x.get() << std::endl;
    x.setter([](int& v, const int& newV){std::cout << "Setter calledn"; v=newV;});
    x.set(2);
    std::cout << x.get() << std::endl;
    return 0;
}

输出:

5
Setter called
2

在线试用

以类似的方式实现 getter 函数应该很容易。