【问题标题】:struct with const member具有 const 成员的结构
【发布时间】:2012-03-02 08:55:23
【问题描述】:

我在使用模板结构时遇到了一些问题。

template<typename T>
struct A{
    const int v1;
    T* v2;
};

我的目的是让v1 始终不可编辑,而如果我使用Tv2 应该是可编辑的,如果我使用const T 作为类型,则不可编辑。

如果我创建构造函数来初始化A,则结构变为:

template<typename T>
struct A{
    const int v1;
    T* v2;
    A() : v1(-1) { v2=NULL; }
    A(int value) : v1(value) { v2=NULL; }
};

然后 g++ 说我需要一个特定的赋值运算符:

错误:非静态常量成员“const int A::v1”,不能使用默认赋值运算符

但我的赋值运算符也应该允许编辑v1。我唯一想避免的是从外部进行编辑,例如:

A a;
a.v1=10;

有没有办法实现这一点(无需创建 getter/setter 或使用指向具有所需值的新 A(int) 的指针)?

如果我将 v1 声明为 const int * 会怎样?它可以以某种方式引用某个值,但不能对其进行编辑。

【问题讨论】:

  • "没有将结构转换为类 (...)" 你所拥有的已经是一个类了。
  • 你必须明白,在 C++ 中,结构是一个类,只是一个非常特定类型的类。结构是一个所有内容都是公开的类。
  • 如果赋值运算符能够修改const 成员,那么您仍然会遇到从外部编辑的问题,因为我只能执行整个对象的赋值自行修改obj.v1
  • @Poodlehat:“结构是一个所有内容都是公开的类”。不,结构是默认情况下成员和基数是公共的类。结构仍然可以有私有成员。基本上你使用structclass 并不重要,只要你保持一致,它所影响的只是你需要输入访问说明符的地方。它还会影响名称的损坏方式。
  • “我的目的是让 v1 始终不可编辑” ...“我的赋值运算符也应该允许编辑 v1”——这是你的问题,直接与要求相矛盾。选择其中一个放弃。

标签: c++ struct constants


【解决方案1】:

这是一种“公开”公共只读数据成员的方法,该成员可由类自己的成员函数(包括赋值)修改:

template <typename T>
class Helper {
    friend class A;
    T *ptr;
    Helper &operator=(const Helper &rhs) = default; // in C++11
    Helper &operator=(const Helper &rhs) { ptr = rhs.ptr; } // in C++03
  public:
    Helper(T *ptr) : ptr(ptr) {}
    operator const int &() const { return *ptr; }
};

class A {
    int v1_;
  public:
    Helper<int> v1;
    A() : v1(&v1_) {} // although `A` should have a constructor that sets `v1_`
    A(const A &rhs) { v1_ = rhs.v1_; v1 = Helper<int>(&v1_); }
    A &operator=(const A &rhs) { v1_ = rhs.v1_; v1 = Helper<int>(&v1_); }
};

现在 A 类以外的任何人都可以使用 v1,但他们唯一可以使用它的目的是获取 const int&amp;v1_ 的引用。

只给A 一个返回const int &amp; 的getter 函数要容易得多,但是如果你真的想要数据成员语法,那么这提供了它...

【讨论】:

  • 看起来比我的解决方案更好。谢谢!
【解决方案2】:

我通过将 v1 的类型从 int 更改为 const int * 解决了我的问题,通过这样做我可以更改 v1 的地址,从而更改 v1 指向的值,但阻止任何类型的编辑。

所以,这是我的新简单结构

template<typename T>
struct A{
    const int* v1;
    T* v2;
};

当我使用带有类型 T 的 A 时,我让 v2 ​​被编辑,而当我使用带有类型 T const 的 A 时,我阻止任何尝试编辑 v2 的指向值。

【讨论】:

    【解决方案3】:

    它说你不能使用 default 赋值运算符。没有什么能阻止您编写自己的operator= 并使用const_cast。不幸的是,这将是未定义的行为,因为 v1 被声明为 const。所以我建议你使用访问器和私有数据。

    【讨论】:

    • 如果你使用const_cast,它仍然是未定义的行为吗?
    • @PaulManta 这里的标准很清楚:const_cast 会导致未定义的行为,如果对象已声明 const。成员变量就是这种情况。我可以挖掘报价,如果它能让你感觉更好。
    • 哦,我明白了。好想你把重点放在“声明”上,我不会注意到的。
    【解决方案4】:

    你可以把它变成一个所有东西都公开的类(这就是一个结构)并使用一个初始化列表——不需要getter/setter

    【讨论】:

    • @pmr - 正确,但如果它是一个常量,我真的更愿意在 ctor 时间设置它。你的解决方案更适合他的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-10
    • 2012-12-12
    • 2012-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多