在 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;
}
我正在处理一个大型代码库,其中有许多 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 的
另外,请不要让你的 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;
}