C++-使用模板公开返回常量引用,私下返回非常量引用
C++ - Using a template to return a const reference publicly and a non const reference privately
问题是:如何使const引用公开返回,而非const引用私下返回
我正试图为类中的一些变量创建一个只读模板。这涉及到一个模板类,该类在公开时返回对数据的常量引用。然而,在类中,我需要对数据进行操作,因此我试图返回一个私下不const的引用。以下是基本信息:
private: operator T&() { return data; }
public: operator const T&() const { return data; }
当我如上所示添加非const引用时,如果我尝试公开访问该变量,我的Visual Studio 2010 cl.exe编译器告诉我它无法访问类中的私有成员。如果使用模板声明x,那么像cout << myobj.x << endl
这样简单的操作将失败
error C2248: 'proxy<T,C>::operator int &' : cannot access private member declared in class 'proxy<T,C>'
这是另一个可供参考的线程:
C++-如何在Visual Studio 2010中实现只读类成员变量-堆栈溢出
编辑:你要的是代码,所以它在这里。
template <class T, class C>
class proxy {
friend C;
private:
T data;
T operator=(const T& arg) { data = arg; return data; }
operator T&() { return data; } // I'd expect this is only returned privately
public:
operator const T&() const { return data; }
};
class myClass {
public:
proxy<int,myClass> x;
void f(int i) {
x = i;
}
};
int main(int argc, char **argv)
{
myClass test;
test.f(12);
cout << test.x << endl; // Compiler error trying to access non-const T&
return 0;
}
实际上,可见性和可访问性在C++中是独立的:
- 可见性规则规定,在解决重载时,将考虑所有成员函数
- 可访问性意味着,如果所选的重载函数不能从所用的上下文中访问(例如,类外的私有成员),则会发生编译器错误
有些人认为,如果函数是从类外调用的,那么私人成员将不会参与过载解决,但事实并非如此。考虑所有功能,无论访问权限如何。
关于你的具体问题,你可以:
std::cout << test.x;
这里test
是非常数,test.x
也是非常数,并且在两个重载转换函数中,选择非常数的一个。但是,唉,这个函数是私有的,因此会导致编译器错误。
快速解决方案是进行const_cast
:
std::cout << const_cast<const myClass&>(test).x;
或者如果你喜欢:
const myClass &ctest = test;
std::cout << ctest.x;
正确的解决方案是只删除非常私人的一个。您不需要它,因为从类上下文中可以直接使用data
成员。
坦率地说,您似乎正在尝试使用其他语言的语法在C++中实现属性。属性很好,但这不是C++的方式。
我的建议是:不要对抗语言,接受语法,只做括号的事情。或者,如果x
不包含不变量,就将其公开。
最短的方法是:
class myClass {
private:
int _x;
public:
int x() const {
return _x;
}
//if needed
void x(int value) {
_x = value;
}
};
将来阅读你的代码的人(请注意,可能是我!)会非常感激你没有尝试重新发明语言。
在C++中,访问检查是在过载解决后进行的。与其他可能性相比,这既有优点也有缺点——从候选集中删除不可访问的函数。
通常,解决方案是为私有函数使用不同的名称。但你似乎在试图符合你交过朋友的一些功能所需的特定界面。我不认为有一个简单的解决办法。私有继承在一般情况下没有帮助,因为继承的函数不是候选集的一部分,它们被派生类中的函数隐藏。但是转换函数是继承的。。。经过测试,原来的问题似乎又出现了(甚至在私有基类中发现了私有转换)。
因此,我最后建议使用命名函数而不是转换,如:
template <typename T, typename C>
class proxy
{
friend C;
private:
T data;
T operator=(const T& arg) { data = arg; return data; }
T& mutate() { return data; }
public:
operator const T&() const { return data; }
};
class myClass
{
public:
proxy<int,myClass> x;
void f(int i)
{
x.mutate() = i;
}
};
test
不是常量,test.x
不是常量,所以myClass::operator int()
比myClass::operator int() const
更匹配。
访问控制(私有/公共)未进入。
- 寿命延长从函数返回引用
- 了解C++如何返回引用并绑定到引用
- 返回引用实例和非引用实例(return mystr & vs mystr)之间的区别是什么?
- 从类返回引用向量
- 使用unique_ptr并返回引用,或者我应该使用shared_ptr并在需要时制作副本
- 混淆C++从函数返回引用
- 两个相同的重载运算符[]一个返回引用
- 为什么向量的.at()成员函数返回引用而不是迭代器
- C++使用和返回引用
- 返回 T 引用的 Const 函子禁止赋值
- 返回引用是否也会延长其生存期?
- 如何返回引用,然后递增迭代器
- 如果使用返回引用的函数初始化"auto"var,为什么它不声明引用类型?
- 我是否需要将 ref 与 make_pair 一起使用才能返回引用?
- 在 vector::at 返回引用后进行更改
- 为什么PyImport_ImportModule返回引用计数为 3 而不是 1 的 PyObject*
- 超出返回引用的单一实例生存期
- Boost.Python 返回引用现有 c++ 对象的 python 对象
- C++ 运算符 += 重载返回引用
- 如何声明接受转发引用并返回引用或副本的函数模板