我正在使用一个库来定义一些数据类型类,这些类通常作为std :: vector<>周围的紧包装实现。类型层次结构是几层深层,大多只添加精心构造的构造函数。
我的问题:基类将其std :: vector定义为private(很好),但只将constor方法添加为const。派生类甚至无法访问它。该库看起来像这样(为清晰起见而缩短):
template <class T> class BaseList
{
public:
BaseList (const T data0) : data_ (1) {
data_[0] = data0; }
const T & operator[] (const size_t nr) const {
// does out off bounds check here
return data_[nr]; }
private:
std::vector<T> data_;
}
class FancyClass : public BaseList<SomeEnumType>
{
public:
FancyClass (const SomeOtherEnumType data0)
: BaseList<SomeEnumType> ( static_cast<SomeEnumType> (data))
{}
}
现在我看来,const定义完全是假的。没有内部方法依赖于向量真正的常量,我的外部代码也没有。
我喜欢做的只是:
strukt MyType {
FancyClass myData;
bool otherData;
}
int main() {
MyType storage = {FancyClass(0), false};
storage.myData[0] = 5;
}
由于常数,这当然不起作用。 (“只读位置的分配”)
责任完全在我身边:是否有一些const_cast魔法可以让这个结构可写? 我知道的唯一另一种可能性是在我的代码中完全复制类型层次结构,但是这仍然会让我在接口库代码时调用很多强制转换或toFancyClass()函数。
任何想法?谢谢!
(请不要评论图书馆的代码质量。如果我可以改变,我不会问这个问题......)
答案 0 :(得分:1)
最简单的是添加运算符[]的非const版本。否则,您可能会通过使用const_cast
来丢弃常量来生成UB。
你可以扔掉这样的常量:
int main() {
MyType storage = {FancyClass(0), false};
const_cast< SomeEnumType& >( storage.myData[0] ) = 5;
}
答案 1 :(得分:1)
现在我看来,const定义完全是假的。没有内部方法依赖于向量真正的常量,我的外部代码也没有。
方法上的const限定符并不意味着它依赖于向量是常量。这意味着该方法不会修改对象的状态。添加它以便编译以下代码。
void f(const FancyClass a)
{
cout<<a[0];
}
如果没有[]
方法上的const限定符,上面的代码就不会编译。
无论如何,以下应该有效
SomeEnumType & r = const_cast<SomeEnumType &>(storage.myData[0]);
r = b;
其中b
是enum
SomeEnumType
但是,如果您的storage
对象实际上是一个const对象,那么它将导致未定义的行为。
答案 2 :(得分:0)
通常,operator []有一对mutable和一个const版本..(参见:Operator overloading)
当然有一个基于const_cast的解决方案,但它涉及未定义的行为(在抛弃constness之后你不允许改变一个值!)