在这样的声明中const的含义是什么?这个常数使我困惑。

class foobar
{
  public:
     operator int () const;
     const char* foo() const;
};

const表示该方法承诺不会更改类的任何成员。即使对象本身被标记为const,也可以执行如此标记的对象成员:

const foobar fb;
fb.foo();

将是合法的。

看看C++中“const”的用法有多少?了解更多信息。


这些常量意味着如果“with const”方法更改内部数据,编译器将出错。

class A
{
public:
    A():member_()
    {
    }

    int hashGetter() const
    {
        state_ = 1;
        return member_;
    }
    int goodGetter() const
    {
        return member_;
    }
    int getter() const
    {
        //member_ = 2; // error
        return member_;
    }
    int badGetter()
    {
        return member_;
    }
private:
    mutable int state_;
    int member_;
};

测试

int main()
{
    const A a1;
    a1.badGetter(); // doesn't work
    a1.goodGetter(); // works
    a1.hashGetter(); // works

    A a2;
    a2.badGetter(); // works
    a2.goodGetter(); // works
    a2.hashGetter(); // works
}

阅读此处了解更多信息


const限定符意味着可以对foobar的任何值调用这些方法。当您考虑对常量对象调用非常量方法时,就会出现不同。考虑您的foobar类型是否具有以下额外的方法声明:

class foobar {
  ...
  const char* bar();
}

方法bar()是非常量的,只能从非常量值访问。

void func1(const foobar& fb1, foobar& fb2) {
  const char* v1 = fb1.bar();  // won't compile
  const char* v2 = fb2.bar();  // works
}

const背后的思想是标记不会改变类内部状态的方法。这是一个强大的概念,但实际上在C++中无法实现。与其说是保证,不如说是承诺。还有一个经常破碎且容易破碎的。

foobar& fbNonConst = const_cast<foobar&>(fb1);

布莱尔的答案是正确的。

但是请注意,有一个可变的限定符可以添加到类的数据成员中。任何标记的成员都可以在const方法中修改,而不违反const约定。

如果您希望对象记住某个特定方法被调用的次数,同时不影响该方法的“逻辑”常量,则可能需要使用这个(例如)。


当您将const关键字添加到方法时,此指针将实质上变为指向const对象的指针,因此您不能更改任何成员数据。(除非您使用mutable,否则稍后将详细介绍)。

const关键字是函数签名的一部分,这意味着您可以实现两个类似的方法,一个在对象为const时调用,另一个则不调用。

#include <iostream>

class MyClass
{
private:
    int counter;
public:
    void Foo()
    { 
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        std::cout << "Foo const" << std::endl;
    }

};

int main()
{
    MyClass cc;
    const MyClass& ccc = cc;
    cc.Foo();
    ccc.Foo();
}

这将输出

Foo
Foo const

在非常量方法中,可以更改实例成员,这在常量版本中是无法做到的。如果将上面示例中的方法声明更改为下面的代码,则会出现一些错误。

    void Foo()
    {
        counter++; //this works
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        counter++; //this will not compile
        std::cout << "Foo const" << std::endl;
    }

这并不完全正确,因为您可以将成员标记为可变的,然后const方法可以更改它。它主要用于内部计数器等。解决方案是以下代码。

#include <iostream>

class MyClass
{
private:
    mutable int counter;
public:

    MyClass() : counter(0) {}

    void Foo()
    {
        counter++;
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        counter++;    // This works because counter is `mutable`
        std::cout << "Foo const" << std::endl;
    }

    int GetInvocations() const
    {
        return counter;
    }
};

int main(void)
{
    MyClass cc;
    const MyClass& ccc = cc;
    cc.Foo();
    ccc.Foo();
    std::cout << "Foo has been invoked " << ccc.GetInvocations() << " times" << std::endl;
}

它将输出

Foo
Foo const
Foo has been invoked 2 times

当您在方法签名中使用const时(如您所说的:constchar*foo()const;)你告诉编译器,这个方法(这里是foo)不能改变它指向的内存。


C++公共知识:基本中级编程中Const成员函数的含义给出了明确的解释:

类的非常量成员函数中此指针的类型X是X*常量。也就是说,它是指向非常数X的常数指针(见Const Pointers和Pointers to Const[7,21])。因为对象它所指的不是常量,可以修改。类型这在类X的常量成员函数中是常量X*const。那个是,它是指向常量X的常量指针。因为它是常量,不能修改。这就是常量和非常量成员函数之间的差异。

因此,在您的代码中:

class foobar
{
  public:
     operator int () const;
     const char* foo() const;
};

你可以这样想:

class foobar
{
  public:
     operator int (const foobar * const this) const;
     const char* foo(const foobar * const this) const;
};

我想补充一点。

也可以将其设置为常量和常量&&

So,

struct s{
    void val1() const {
     // *this is const here. Hence this function cannot modify any member of *this
    }
    void val2() const & {
    // *this is const& here
    }
    void val3() const && {
    // The object calling this function should be const rvalue only.
    }
    void val4() && {
    // The object calling this function should be rvalue reference only.
    }

};

int main(){
  s a;
  a.val1(); //okay
  a.val2(); //okay
  // a.val3() not okay, a is not rvalue will be okay if called like
  std::move(a).val3(); // okay, move makes it a rvalue
}

请随意改进答案。我不是专家


与函数声明一起使用的const关键字指定它是一个const成员函数,它将无法更改对象的数据成员。


https://isocpp.org/wiki/faq/const-correctness#const-成员fns

什么是“常量成员函数”?检查(而不是变异)其对象的成员函数。常量成员函数由位于成员函数参数列表后面的常量后缀表示。带有常量后缀的成员函数被称为“常量成员函数”或“检查器”。没有常量后缀的会员函数称为“非常量成员函数”和“赋值函数”弗雷德班{公众:void inspect()常量;//该成员承诺不会改变*这一点void mutate();//此成员函数可能会更改*此};void userCode(Fred可更改,常量Fred不可更改){changed.inspect();//好:不更改可更改对象changed.mutate();//好:更改一个可更改的对象不可更改的.inspect();//好:不更改不可更改的对象不可更改。mutate();//错误:尝试更改不可更改的对象}试图调用不可更改的.amutate()是在编译时捕获的错误。const没有运行时空间或速度损失,您不需要编写测试用例来在运行时检查它。应使用inspect()成员函数上的尾随常量表示该方法不会更改对象的抽象(客户端可见)状态。这与表示该方法不会更改对象结构的“原始位”略有不同。C++编译器不允许采用“逐位”解释,除非它们能够解决通常无法解决的别名问题(即,可能存在一个非常量的别名,可以修改对象的状态)。这个别名问题的另一个(重要)见解是:用指向常量的指针指向对象并不能保证对象不会改变;它只是承诺对象不会通过该指针发生更改。


这里const表示在该函数中任何变量的值都不能改变

class Test{
private:
    int a;
public:
    void test()const{
        a = 10;
    }
};

像这个例子一样,如果你试图改变测试函数中变量的值,你会得到一个错误。


在常量对象中,只能调用常量方法。这种方法中的所有字段都被视为常量字段。最后一个问题产生了奇怪的影响:

指针变为const指针int*const,这与指向const const int*的指针不同。因此,您可以更改指针指向的对象,但不能使指针指向另一个对象。引用应该成为常量引用,但它始终是常量引用:不能将其重新初始化为另一个对象。但是,您可以再次更改引用引用的对象。