【问题标题】:Using 'const' in class's functions [duplicate]在类的函数中使用“const”[重复]
【发布时间】:2011-01-10 13:50:44
【问题描述】:

我在类中看到了很多将 const 关键字放在函数之后的用法,所以我想知道它是关于什么的。我在这里阅读了smth:http://duramecho.com/ComputerInformation/WhyHowCppConst.html

它说使用 const 是因为函数“可以尝试更改对象中的任何成员变量”。如果这是真的,那么它应该在任何地方使用,因为我不希望以任何方式更改或更改任何成员变量。

class Class2
{ void Method1() const;
  int MemberVariable1;} 

那么, const 的真正定义和用途是什么?

【问题讨论】:

  • 如果你的成员变量从不改变,为什么还要有成员变量?
  • 因为他想要一个不可变的类?这并非不合理。
  • 我不是一个真正的 C++ 人,所以这更像是一个有趣的问题,而不是一个“陷阱”问题。如果您希望它真正不可变,为什么不将所有成员声明为“const”?还是你们都将成员声明为 const 并将方法声明为 const?
  • 我可能只是将方法声明为 const,但您可以两者都做。不过,这并不是一个真正适合在评论中描述的主题。
  • @GMan:令人遗憾的是,人们根据他们预期的“声誉收入”选择性地回答问题,而不是仅仅向有需要的人伸出援助之手。

标签: c++ oop class constants


【解决方案1】:

可以在 const 对象上调用 const 方法:

class CL2
{
public:
    void const_method() const;
    void method();

private:
    int x;
};


const CL2 co;
CL2 o;

co.const_method();  // legal
co.method();        // illegal, can't call regular method on const object
o.const_method();   // legal, can call const method on a regulard object
o.method();         // legal

此外,它还告诉编译器 const 方法不应该改变对象的状态,并且会捕捉到这些问题:

void CL2::const_method() const
{
    x = 3;   // illegal, can't modify a member in a const object
}

使用 mutable 修饰符对上述规则有一个例外,但在进入该领域之前,您应该先熟悉 const 的正确性。

【讨论】:

  • 为了安全起见,是否应该为所有不会改变对象状态的方法提供 const? (例如吸气剂)
  • 为了 const 的正确性,是的。
【解决方案2】:

其他人已经回答了你关于 const 成员函数的技术方面的问题,但这里有一个更大的图景——这就是 const correctness 的想法。

长话短说,const 正确性是关于澄清和强制执行代码的语义。举一个简单的例子。看看这个函数声明:

bool DoTheThing(char* message);

假设别人写了这个函数,你需要调用它。你知道DoTheThing() 对你的字符缓冲区做了什么吗?也许它只是将消息记录到文件中,或者它可能会更改字符串。仅通过查看函数声明,您无法判断调用的语义是什么。如果函数没有修改字符串,那么声明是不正确的。

使你的函数 const 正确也有实际价值。也就是说,根据调用的上下文,您可能无法在没有一些技巧的情况下调用 const 不正确的函数。例如,假设您知道DoTheThing() 不会修改传递给它的字符串的内容,并且您有以下代码:

void MyFunction()
{
  std::string msg = "Hello, const correctness";
  DoTheThing(msg.c_str());
}

上面的代码无法编译,因为msg.c_str() 返回一个const char*。为了编译这段代码,你必须做这样的事情:

void MyFunction()
{
  std::string msg = "Hello, const correctness";
  DoTheThing(msg.begin());
}

...甚至更糟:

void MyFunction()
{
  std::string msg = "Hello, const correctness";
  DoTheThing(const_cast<char*>(msg.c_str()));
}

可以说,它们都不比原始代码“更好”。但是因为DoTheThing() 是以不正确的方式编写的,所以你必须绕着它弯曲你的代码。

【讨论】:

    【解决方案3】:

    const,当附加到非静态类方法时,告诉编译器你的函数不会修改对象的内部状态。

    这在两个方面很有用:

    • 如果您确实在 const 方法中编写了更改内部状态的代码,编译器会捕获错误,将编程错误从运行时转移到编译时。
    • 如果客户端代码在常量指针上调用非 const 方法,编译器会捕获错误,确保“不改变事物的链”得以维持。

    通常您希望将所有非变异的非静态类方法声明为 const。这允许调用代码在指针上使用 const 限定符,它有助于捕获错误。

    典型的 C++:您可以声明一个类成员变量“可变”,然后从 const 方法甚至更改它。

    【讨论】:

      【解决方案4】:

      意思是你向调用 const 函数成员的客户保证对象的状态不会改变。因此,当你说一个成员函数是 const 时,这意味着你在函数调用期间不会更改任何对象的成员变量。

      【讨论】:

      • 这并不完全正确 - 可观察的行为不会改变,但如果标记为 mutable,则成员数据可以。例如,这允许缓存一次计算的结果。
      • 情况更糟。如果您有一个指向某些数据的指针,则成员函数后面的const 只保证指针不变,而不是它指向的数据。然而,数据通常被认为是对象状态的一部分。因此,实际上,const 仅阻止成员函数更改对象的成员数据,而不是其所有状态。它强制执行按位常量,而不是逻辑常量。
      • 确实,它只强制执行按位常量,并且当您将成员设置为可变时,所有赌注都将关闭。这只是对编译器的真正提示,Klatchko 先生在上面有更好的解释。
      【解决方案5】:

      如果这是真的,那么是否应该在任何地方使用它,因为我不希望任何成员变量以任何方式被改变或改变?

      嗯,不。有时您确实需要实例方法来修改成员。例如,任何 set 方法显然都需要设置变量,因此不应将 const 放在任何地方。但是,如果您的对象的状态是完全不可变的,首先考虑是否完全没有实例(即静态类)是否会更好,如果不是这样,则将所有内容都设置为const

      【讨论】:

        【解决方案6】:

        不希望更改任何成员变量是很不寻常的,但如果这是您的类所需要的,那么您应该将所有成员函数设为 const。

        但是,您可能确实想更改至少一些成员:

        class A {
          private: 
            int val;
          public:
            A() : val(0) {}
            void Inc() { val++; }
            int GetVal() const { return val; };
        };
        

        现在,如果我创建 A 的两个实例:

        A a1;
        const A a2;
        

        我可以说:

        a1.GetVal();
        a2.GetVal();
        

        但我只能说:

        a1.Inc();
        

        试图改变一个常量对象的值:

        a2.Inc();
        

        给出编译错误。

        【讨论】:

        • 不改变外部状态的方法在声明式编程中更为常见——诚然,目前在 C++ 中这不是最简单的事情。但更流畅的 C++ 库设计正在开发中(例如Ranges v3),这将使这在未来更加实用。
        【解决方案7】:

        在方法之后使用的 const 关键字表明此方法不会修改调用它的对象。这样,可以在对象的 const 版本上调用此方法。

        【讨论】:

          猜你喜欢
          • 2022-01-13
          • 1970-01-01
          • 2014-12-22
          • 1970-01-01
          • 2018-09-21
          • 1970-01-01
          • 1970-01-01
          • 2012-06-14
          • 1970-01-01
          相关资源
          最近更新 更多