【问题标题】:Should members usually not be const in C++ classes? The actual purpose of const membersC++ 类中的成员通常不应该是 const 吗? const 成员的实际用途
【发布时间】:2013-02-21 18:12:51
【问题描述】:

起初,我的印象是成员变量在 C++ 类中通常应该是 const,除非我希望它的成员函数在内部为每个对象修改这些变量(我通常将变量放入私有:)。

但我现在发现我可能一直都错了。例如我不能再分配给这样的对象了。我什至不能做 move-assign。

以 std::string 为例。你可以这样做:

std::string foo("foo");
foo = std::string("bar");

这意味着在内部,std::string 只有非常量成员变量,对吧?

我的想法对吗?对于 C++ 来说相对较新,它的新思维有点奇怪。 const 的目的可能不是我想的那样。

那么拥有 const 成员变量的实际目的是什么?

【问题讨论】:

    标签: c++


    【解决方案1】:

    C++ 类中的成员通常不应该是 const 吗?

    我建议您忽略“通常”如何声明变量。 const 出现的频率 不是让你决定你要声明的 next 变量是否是const 的东西。

    如果在整个程序执行过程中初始化后成员的值不应该改变,则成员应该是const。否则,它们不应该是const。这是数据的语义属性,决定是否创建变量 const 的唯一标准是变量在值更改方面的性质。

    它可以改变,还是保持不变? 在后一种情况下,一定要做const

    这意味着在内部,std::string 只有非常量成员变量,对吧?

    ,这并不意味着它,尽管std::string 可能恰好是这种情况。

    重要的是,你的类中不存在只有 const 成员(当然,只要你想离开它并且你的类封装了一些资源),这样那些实际上可以用来判断一个对象是否被移动的成员是可修改的。

    当你离开一个物体时,你留下的是一个骨架。移动构造函数或移动赋值运算符需要一种方法来“标记”这个被移动的对象作为骨架。通常,这很自然地源于从对象中“窃取内脏”的过程,即复制一些指针并将它们设置为 null - 这样,析构函数和赋值运算符就不会尝试释放它们。为了将移动对象标记为“僵尸”,显然您需要 一些 可修改的成员变量。

    但是,在你的班级中有一些const 成员并没有错。 const 是一个重要的修饰符,它使您的程序的语义更加清晰,并且您的程序不太可能破坏它。 只要合适(即,只要 A 变量的值在初始化后的整个程序执行过程中都不会改变),使用它

    简单地说,const 成员变量不会被移动构造函数或移动赋值运算符修改(事实上,它们不会被 any 函数修改);但同样,这并不意味着他们不能在场。

    【讨论】:

      【解决方案2】:

      我的印象是成员变量在 C++ 类中通常应该是 const,除非我希望它的成员函数来修改这些变量

      你忘记的是赋值运算符,包括默认的,一个成员函数。示例:

      struct Foo {
          const int i = 0;
      
          Foo& operator =(const Foo& src)
          {
              if (&src == this)
                  return *this;
              i = src.i;
              return *this;
          }
      };
      

      由于赋值运算符是成员函数,显然它必须能够修改Foo::i。如果没有,则不能调用它。请记住,鉴于Foo 对象ab,这是:

      a = b;
      

      实际上是语法糖:

      a.operator= (b);
      

      还要记住,在这种情况下,默认赋值运算符会被删除,因为Foo::iconst。这意味着如果您自己不编写,Foo 完全没有赋值运算符。

      【讨论】:

        【解决方案3】:

        const 对象是您不想更改的对象,它们在程序执行期间保持不变。您可以在类的构造函数的成员初始化列表中为它们分配一个值,但不能超出此范围。如果你有一个变量可以有不同的值,你不应该使用 const。

        【讨论】:

          【解决方案4】:

          我首先建议您查看this related question 的答案。

          快速而肮脏的答案是 const 成员属性包含在对象初始化后保持不变的值。复制操作正在尝试执行导致构造新对象的操作,然后将旧对象的值分配给新对象(在隐式复制构造函数主体中)。作为解决方案,您最可能想要的是创建一个显式复制构造函数,它将原始对象作为参数并初始化初始化列表中的 const 属性值。

          复制构造器示例:

          ClassWithConstantProperties( const ClassWithConstantProperties &orig) :
              constProperty1(orig.constProperty1)
              constProperty2(orig.constProperty2)
          {
          }
          

          This tutorial 更全面地解释了 C++ 中隐式定义的类的构造函数,并且还在一个优秀的 C++ 参考页面上。

          【讨论】:

            【解决方案5】:

            这取决于对象,但一般来说,当您编写 一个对象的代码,负责它的不变量。 我很少使用const 或引用成员,但它们是 在不支持作业的课程中完全可以接受。

            通常,const 用作逻辑常量,而不是按位常量。 而 const 更像是你和你的客户之间的契约, 而不是保护你免受自己伤害的东西。在这个 意义,具有 const 函数,返回 const 引用,以及 将 const 引用作为参数很有意义。最佳 参数上的级别 const 或类中的 const 并不是真的 然而,意义重大。

            【讨论】:

              【解决方案6】:

              在构造后不应在类内部更改值时使用常量变量。
              一些示例:数字常量(pi、e)和引用。

              struct Database_Record
              {
                  Database_Record(const std::string& table_name)
                    : m_table_name(table_name)
                  { ; }
                  const std::string& get_table_name(void) const
                  {  return m_table_name; }
              private:
                  const std::string m_table_name;
              };
              

              在上述表示数据库记录的结构中,它有一个与记录关联的表名,初始化后不能更改;这可以防止记录被写入错误的表。

              【讨论】:

                【解决方案7】:

                类的数据成员描述了该类型对象的状态。 const 数据成员意味着对象具有永远不会改变的状态。这不是很常见。通常const 成员也是static

                const 数据成员唯一能做的就是将它初始化为构造函数的成员初始化列表。

                您可以从另一个std::string 分配给std::string 的事实仅意味着它的复制赋值运算符不会对其const 数据成员做任何事情(因为它当然不能)。

                具有const 数据成员的类或结构将没有隐式默认的复制赋值运算符。编译器无法分配给您的 const 数据成员,所以它只会说“如果您想分配,您必须自己定义它。”

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2013-04-25
                  • 2011-06-04
                  • 2020-11-21
                  • 2011-03-23
                  • 1970-01-01
                  • 2016-05-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多