gpt4 book ai didi

c++ - 如何处理const对象中非const引用成员的初始化?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:06:53 25 4
gpt4 key购买 nike

假设你有一个类

    class C 
{
int * i;

public:

C(int * v):i(v) {};

void method() const; //this method does not change i
void method(); //this method changes i
}

现在你可能想定义这个类的常量实例

    const int * k = whatever;
const C c1(k); //this will fail

但这会失败,因为非 const int C 的构造函数 C(int * v)

所以你定义了一个const int构造函数

    C(const int * v):i(v) {}; //this will fail also

但这也会失败,因为 C 的成员“int * i”是非常量。

遇到这种情况怎么办?使用可变的?铸件?准备类的 const 版本?

编辑:在与 Pavel(下)讨论后,我对这个问题进行了一些调查。对我来说,C++ 所做的是不正确的。指针目标应该是严格类型,这意味着您不能执行以下操作:

int i;
const int * ptr;
ptr = & i;

在这种情况下,语言语法将 const 视为不更改指针目标的 promise 。此外,int * const ptr promise 不会更改指针值本身。因此,您有两个地方可以应用 const。那么您可能希望您的类(class)模拟一个指针(为什么不呢)。在这里,事情正在分崩离析。 C++ 语法提供了 const 方法,这些方法能够保证不会更改字段的值本身,但是没有语法指出您的方法不会更改类内指针的目标。

解决方法是定义两个类,例如 const_CC。然而,这不是一条皇家之路。使用模板,他们的部分特化很难不陷入困惑。还有所有可能的参数变体,如 const const_C & argconst C & argconst_C & argC & arg 看起来不漂亮。我真的不知道该怎么办。使用单独的类或 const_casts,每种方式似乎都是错误的。

在这两种情况下,我都应该将不修改指针目标的方法标记为常量吗?或者只是遵循 const 方法本身不改变对象状态的传统路径(const 方法不关心指针目标)。那么在我的例子中,所有方法都是 const,因为类正在对指针建模,因此指针本身是 T * const。但很明显,其中一些修改了指针的目标,而另一些则没有。

最佳答案

听起来你想要一个可以包装 int*(然后表现为非常量)或 int const*(然后表现为 const)的对象.你不能真正用一个类来正确地完成它。

事实上,const 应用于您的类的想法应该像那样改变它的语义是错误的 - 如果您的类模拟指针或迭代器(如果它包装了一个指针,它很可能是这种情况),那么应用于它的 const 应该只意味着它不能自己改变,并且不应该暗示任何关于指向的值。您应该考虑遵循 STL 为其容器所做的工作 - 这正是它具有不同的 iteratorconst_iterator 类的原因,两者都是不同的,但前者可以隐式转换为后者.同样,在 STL 中,const iteratorconst_iterator 不同!因此,只需执行相同的操作即可。

[EDIT] 这里有一个巧妙的方法,可以最大限度地重用 Cconst_C 之间的代码,同时确保整个过程中的 const 正确性,而不是深入研究U.B. (使用 const_cast):

template<class T, bool IsConst>
struct pointer_to_maybe_const;

template<class T>
struct pointer_to_maybe_const<T, true> { typedef const T* type; };

template<class T>
struct pointer_to_maybe_const<T, false> { typedef T* type; };

template<bool IsConst>
struct C_fields {
typename pointer_to_maybe_const<int, IsConst>::type i;
// repeat for all fields
};


template<class Derived>
class const_C_base {
public:
int method() const { // non-mutating method example
return *self().i;
}
private:
const Derived& self() const { return *static_cast<const Derived*>(this); }
};

template<class Derived>
class C_base : public const_C_base<Derived> {
public:
int method() { // mutating method example
return ++*self().i;
}
private:
Derived& self() { return *static_cast<Derived*>(this); }
};


class const_C : public const_C_base<const_C>, private C_fields<true> {
friend class const_C_base<const_C>;
};

class C : public C_base<C>, private C_fields<false> {
friend class C_base<C>;
};

如果您实际上只有很少的字段,那么在两个类中复制它们可能比使用结构更容易。如果有很多,但它们都是同一类型,那么直接将该类型作为类型参数传递会更简单,而不必费心使用 const 包装器模板。

关于c++ - 如何处理const对象中非const引用成员的初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1699307/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com