Edit1:我意识到如果不了解我正在尝试做什么,就很难理解这个问题。 A类不完整,但它基本上代表C阵列“代理”(或“查看器”或“采样器”)。一个有趣的用法是将C阵列作为2d网格(此处未显示相关功能)。该类的属性如下:
请不要质疑目的或设计:它们是问题的假设。
首先是一些代码:
class A
{
private:
float* m_pt;
public:
A(float* pt)
:m_pt(pt)
{}
const float* get() const
{
return m_pt;
}
void set(float pt)
{
*m_pt = pt;
}
};
void gfi()
{
float value = 1.0f;
const A ac(&value);
std::cout<<(*ac.get())<<std::endl;
A a = ac;
a.set(2.0f);
std::cout<<(*ac.get())<<std::endl;
}
调用“gfi”会生成以下输出:
1
2
使用 ac 分配 a 是一种缩短 ac 常量的便宜方法。 有没有更好的方法来保护 m_pt 指向的值?
请注意,我希望我的类可以复制/赋值,我只是不希望它在此过程中松开它的常量。
Edit0:我也想在那里有一个指针,请不要深刻的复制(请说指针可以是一个巨大的数组)。
Edit2:感谢答案,我得出的结论是“const构造函数”是一个有用的东西(至少在这个上下文中)。我查了一下,当然我不是那个得出这个结论的人。这是一个有趣的讨论: http://www.rhinocerus.net/forum/language-c-moderated/569757-const-constructor.html
Edit3:终于得到了一些我很满意的东西。谢谢你的帮助。进一步的反馈非常受欢迎
template<typename T>
class proxy
{
public:
typedef T elem_t;
typedef typename boost::remove_const<T>::type elem_unconst_t;
typedef typename boost::add_const<T>::type elem_const_t;
public:
elem_t* m_data;
public:
proxy(elem_t* data = 0)
:m_data(data)
{}
operator proxy<elem_const_t>()
{
return proxy<elem_const_t>(m_data);
}
}; // end of class proxy
void test()
{
int i = 3;
proxy<int> a(&i);
proxy<int> b(&i);
proxy<const int> ac(&i);
proxy<const int> bc(&i);
proxy<const int> cc = a;
a=b;
ac=bc;
ac=a;
//a=ac; // error C2679: binary '=' : no operator found which takes a right-hand operand of type...
//ac.m_data[0]=2; // error C3892: 'ac' : you cannot assign to a variable that is const
a.m_data[0]=2;
}
答案 0 :(得分:2)
你的班级设计糟糕:
或者,您应该通过将复制构造函数和赋值设置为私有而不是实现它们来防止复制和赋值。
答案 1 :(得分:1)
您可以使用代理模式和其他运行时constness布尔成员进行欺骗。但首先,请告诉我们原因。
答案 2 :(得分:1)
实际上,您的类就像一个只能看到一个值的迭代器。它不会仅仅指向您的数据封装。
您遇到的问题已经解决,迭代器您应该阅读有关创建自己的iterator
和const_iterator
对的一些文档,以了解如何执行此操作。
注意:通常,const iterator
是一个迭代器,不能递增/递减,但可以更改它指向的值。其中const_iterator
是一个不同的类,可以递增/递减,但它指向的值不能改变。
这与const float *
和float *const
之间的差异相同。在您的情况下,A
与float *
相同,const A
与float *const
相同。
对我来说,你的选择似乎是:
const A
的副本,例如签名为A(A & a);
答案 3 :(得分:0)
为什么不在A中将float*
替换为float
。如果float
的原始所有者float*
引用可以更改它,或者任何人准备对来自a::get
的返回值进行可变投射。
答案 4 :(得分:0)
const
总是只是对编译器的提示;没有办法让变量永久只读。
答案 5 :(得分:0)
我认为你应该使用深层复制并定义你自己的赋值运算符和复制构造函数。还要在不太好的实践中返回内部数据结构的句柄。
答案 6 :(得分:0)
//--------------------------------------------------------------------------------
class CNotSoConstPointer
{
float *mp_value;
public:
CNotSoConstPointer(float *ip_value) : mp_value(ip_value) {}
void ModifyWithConst(float i_value) const
{
mp_value[0] = i_value;
}
float GetValue() const
{
return mp_value[0];
}
};
//--------------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
float value = 12;
const CNotSoConstPointer b(&value);
std::cout << b.GetValue() << std::endl;
b.ModifyWithConst(15);
std::cout << b.GetValue() << std::endl;
while(!_kbhit()) {}
return 0;
}
这将输出12然后15,而不是“聪明”关于const not-so-const对象的const-correctness。原因是只有指针ITSELF是const,而不是它指向的内存。
如果后者是您想要的,那么您需要更多的包装以获得您想要的行为,例如我在下面的原始建议或Iain建议。
原始回答:
您可以为数组代理创建一个模板,专门针对const版本的const数组。专用版本将有一个const * m_pt,返回一个const指针,当你尝试设置时抛出一个错误,等等。
编辑:这样的事情:
template<typename T>
class TProxy
{
T m_value;
public:
TProxy(T i_t) : m_value(i_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.m_value) {}
T get() { return m_value; }
void set(T i_t) { m_value = i_t; }
};
template<typename T>
class TProxy<const T *>
{
const T *mp_value;
public:
TProxy(const T *ip_t) : mp_value(ip_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.mp_value) {}
T get() { return m_value; }
};
答案 7 :(得分:0)
您可以拒绝某些参数组合的复制构造函数:
例如,添加构造函数;
A(A& a) :m_pt(a.m_pt) { m_pt = a.m_pt; }
阻止使用const A
初始化A的任何实例。
这也会阻止{1}} a1是const,但你永远不需要这样做,因为你可以直接使用a1 - 即使你可以复制它也是const,a2将永远相同A1。