web-dev-qa-db-ja.com

クラスの関数宣言の最後の 'const'の意味は?

このような宣言におけるconstの意味は何ですか? constは私を混乱させる。

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

constキーワードをメソッドに追加すると、thisポインタは基本的にconstオブジェクトへのポインタになるため、メンバーデータを変更することはできません。 (あなたがmutableを使わない限り、後でもっと詳しく)。

constキーワードはfunctionsシグネチャの一部です。つまり、オブジェクトがconstのときに呼び出されるメソッドとそうでないメソッドの2つを実装できます。

#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

Non-constメソッドではインスタンスメンバーを変更できますが、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;
    }

メンバーをmutableとしてマークし、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++;
        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 << "The MyClass instance has been invoked " << ccc.GetInvocations() << " times" << endl;
}

どちらが出力されます

Foo
Foo const
The MyClass instance has been invoked 2 times
855

Constは、メソッドがクラスのメンバを変更しないことを約束することを意味します。オブジェクト自体がconstとマークされていても、そのようにマークされているオブジェクトのメンバーを実行することができます。

const foobar fb;
fb.foo();

合法です。

を参照してください。C++でのconstの使用方法はいくつですか。 詳細については。

174
Blair Conrad

const修飾子は、メソッドがfoobarの任意の値で呼び出すことができることを意味します。違いは、constオブジェクトに対してnon-constメソッドを呼び出すことを検討したときです。あなたのfoobar型が以下の追加のメソッド宣言を持っていたかどうかを考えてください。

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

メソッドbar()は非constであり、非const値からのみアクセスできます。

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);
43
JaredPar

これらの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
}

詳細については this を読んでください。

22
Mykola Golubyev

ブレアの答えは目の前にあります。

ただし、クラスのデータメンバに追加できるmutable修飾子があります。 canとマークされたメンバーは、const規約に違反することなくconstメソッドで変更できます。

特定のメソッドが呼び出された回数をオブジェクトに記憶させ、そのメソッドの「論理的」な制約には影響を与えない場合は、これを使用することをお勧めします。

10
Alnitak

定数メンバ関数の意味 in C++共通知識:基本的な中級プログラミング は明確な説明を与える

クラスXの非constメンバー関数内のthisポインターの型はX * constです。つまり、これは非定数Xへの定数ポインタです(Const PointersおよびConstへのポインタ[7、21]を参照)。これが参照するオブジェクトはconstではないため、変更することができます。クラスXのconstメンバー関数内のthisの型はconst X * constです。これは定数Xへの定数ポインタです。これが参照するオブジェクトはconstなので、変更することはできません。それがconstとnon-constメンバー関数の違いです。

だからあなたのコードで:

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;
};
8
Nan Xiao

メソッドシグネチャにconstを使用すると(あなたが言ったように:const char* foo() const;)、thisが指すメモリはこのメソッドでは変更できないことをコンパイラに伝えています(ここではfoo)。

6
Matrix Buster

次の点を付け加えたいと思います。

それをconst &const &&にすることもできます

そう、

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
}

答えを改善すること自由に感じなさい。私は専門家ではありません

2
coder3101

関数宣言で使用されるconstキーワードは、それがconstメンバー関数であり、それが変更不可のデータメンバーであることを指定しますオブジェクト。

0
Chandra Shekhar