在 C++ 中是否可以通过类似 属性 的语法调用访问器?

In C++ is it possible to call an accessor through property-like syntax?

我正在处理一个大型代码库,其中有许多 public 刚刚定义的变量。不幸的是,访问这些变量的功能已经改变,这个新功能最好由 public 访问器和一个私有实例变量封装。

所以,我正在尝试进行此更改。为此,我计划将每个 public 属性 设为私有,然后创建访问器。但是,我不想更改任何访问旧 public 属性的代码。例如:

将 public 属性 更改为私有后,我有以下 class:

class Test {

    private:
        int item = 5;

    public:
        int GetItem() {
             return item;
        };

        void SetItem(int new_item) {
             item = new_item;
        };
};

以前,"item"曾经是class的public属性,通过:

访问
Test* t = new Test();
int item = t->item;

不过现在,我需要为 "item" 的检索方式添加新功能。例如:

int GetItem() {
     //  Some complicated code which changes "item"
     return item;
};

如何保持相同的语法:

int item = t->item;

但实际执行:

int item = t->GetItem();

非常感谢任何帮助!

如果您的问题是因为您不想调用 2 个不同的函数来设置和获取,您可以创建一个 return 成员引用的函数:

int& Item()
{
     // Some complicated code which changes *items
     return item;
}

如您所见,return 类型是 int& 而不是 int。所以你可以这样使用这个函数

t.Item() = someValue;

您可以使 int item = t.item; 工作,方法是将 item 定义为类型为辅助 class 且定义了自定义转换 operator int() 的成员变量。另外,operator=(int new_value)拦截集合操作。

你做不到的是

int& item = t.item;

int* pitem = &t.item;

因为这两者都支持直接内存访问,无需经过任何 getter 或 setter。在创建引用或指针时,您甚至无法确定会有多少次访问或读取或写入。

C++ 是一种编译型非反射语言,即你不能只是 "look names up as you access an element",因为在二进制文件中,不再有名称。

所以,不,你想要的是不可能的。 (至少不是没有限制——参见 Ben Voigt 的 ;有一个 "transparent" 属性 实际上是一个 getter 调用肯定不值得你正在构建的陷阱那个-)

另外,请不要让你的 C++ 变成 Java 只是为了拥有 getters 和 setter——如果它们实际上没有增加安全性,我真的不明白使用它们的意义

要扩展 Ben Voight 的答案,您可以定义一个代理模板,允许在没有样板的情况下进行此操作:

template <typename Return, typename Containing, Return (Containing::* func)()>
struct proxy
{
   Containing& c;
   proxy(Containing& c) : c(c) {}
   operator Return() { return (c.*func)(); }
   Return& operator=(const Return& r) { return (c.*set)() = r; }
 };

然后定义一个"property"

class c {
   int y_;
   int get_y() { std::cout << "Getting y" << std::endl; return y_; }
public:
   proxy<int, x, &x::get_y> y;
   c() : y(*this) {}
};

在客户端代码中

int main() {
   c val;
   val.y = 5;
   std::cout << val.y << std::endl;
}