是否可以同时声明一个类成员的常量/非常量?

Is it possible to declare a class member both const/non-const?

本文关键字:常量 成员 一个 非常 声明 是否      更新时间:2023-10-16

我有一个类,它可以将非常量指针或常量指针作为其重载构造函数的参数。在我的特殊情况下,我需要从类Tconstnon-const方法实例化此类的对象,但它从 const 方法失败,因为它无法将 const 指针分配给foo

myClass() {
public:
myClass(T* v);
myClass(const T* v);
// ...
T* foo;
// ...
}

是否可以将两个构造函数中的参数分配给foo?如果是这样,正确的语法是什么?

编辑:

在更具体的情况下,我有一个类myClass,它环绕std::vector并允许我通过嵌套类mySubset直接访问向量的子集:

template<typename _type>
myClass() {
std::vector<_type> data;
public:
class mySubset(){
myClass<type>* foo;
public:
mySubset(myClass<_type>* _in) { foo = _in; };
mySubset(const myClass<_type>* _in) { foo = _in; /* error */ };
// ...
}
// ...
myClass();
// ...
void mySubset method() { return mySubset(this); };;
void mySubset const_method const() { return mySubset(this); /* error */ };
// ...
}

其中的代码是无关紧要的 - 基本上mySubset允许读取和写入特定的向量位置。虽然我能够通过单独的 const 和非 const 嵌套类实现我想要的东西,但我正在寻找一种使用单个返回类型来实现这一点的方法。

我认为你必须重新考虑你的设计,因为你不能用const T*的左值初始化一个T*,没有const_cast应该避免,除非你真的确定,(因为如果你试图在丢弃常量后修改常量指针,它会调用一个未定义的行为)

相反,您可以使用模板类型推断来constnon const

template <typename T>
class myClass {
public:
//myClass(T* v):foo(v) { }
myClass( T* v):foo(v)
{
}
// ...
T* foo;
// ...
};

然后

int a =42;
const int* p1 = &a;
int *p2 = &a;
myClass  X1(p1); //C++17 auto type deduction or use myClass<const int> X1(p1)
myClass  X2(p2);

您可以在const T*构造函数中使用const_cast,但通常不应该使用。

const T*表示"指向常量值 T",并且您存储"指向 T 的指针"。 如果你执行 const 强制转换,你最终可能会修改一个不应该修改的值。 如果你不打算修改foo,只需const T*声明它,只使用单个const T*构造函数。

我会检查一下这是否是设计问题。 很多时候会出现这些场景: (1) 你在哪里存储一个指向非常量的东西的指针,而它应该是常量。 通常,这是因为您正在访问另一个对象中的值,并且您应该在每个使用站点上将该对象作为(可能是 consst)引用传递,而不是存储指向它的指针。 (2)当你真的想存储一个对象的副本时,在这种情况下,你只需保留一个常规T并将其作为构造函数中的const T&传入。 (3) 您正在处理原始的 C 样式字符串,并希望将内容复制到您自己的缓冲区中。

如果您不想使用参数化类型(模板)类作为@P0W的答案,则不可能仅使用一个指针来接受所有常量和非常量指针类型。您需要另一个常量指针类型才能仅接受包装类中的const <your another class> *。 下面的代码在包装类中有两个单独的指针类型后工作,你可能不喜欢。

#include <iostream>
using namespace std;
class SomeObject {
public:
SomeObject(){}
explicit SomeObject(int i):testVal(i){}
private:
int testVal;
};
class PtWrapper {
public:
PtWrapper(SomeObject *pso);
PtWrapper(const SomeObject *cpso);
private:
SomeObject *pSO;
const SomeObject *cpSO;
};

int main(int argc, char *argv[]) {
SomeObject so(133);
SomeObject *pso = &so;
const SomeObject cso(166);
const SomeObject *cpso = &cso;
PtWrapper pw1(pso);
PtWrapper pw2(cpso);
return 0;
}
PtWrapper::PtWrapper(SomeObject *pso) :pSO(pso){
}
PtWrapper::PtWrapper(const SomeObject *cpso):cpSO(cpso){}