「const」の意味は、クラスの関数宣言で最後ですか?


727

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

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

回答:


951

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

constキーワードは2つの類似した方法で、オブジェクトがあるときに呼び出される1実装できることを意味機能の署名の一部であり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

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;
    }

メンバーをとしてマークしmutableconstメソッドがメンバーを変更できるため、これは完全には当てはまりません。主に内部カウンターなどに使用されます。その解決策は以下のコードです。

#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

187

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

const foobar fb;
fb.foo();

合法です。

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


47

const方法は、任意の値に呼び出すことができるという修飾子の手段foobar。違いは、constオブジェクトで非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);

3
答えはconstオブジェクトではなく、他のconstメソッドに関するものだと思いました。
Mykola Golubyev、2009

constしかし、背後にある考えは、クラスの内部状態を変更しないメソッドをマークすることです」に感謝します。それが本当に私が探していたものです。
kovac

1
@JaredParは、読み取り専用操作を表すメンバー関数をマークする必要があることを意味しますconstか?
kovac

26

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

詳細については、こちらをお読みください


1
可変性constについて言及していないメンバー関数に関する質問は、せいぜい不完全です。
IInspectable 2015

13

ブレアの答えは目立っている。

ただしmutable、クラスのデータメンバーに追加できる修飾子があることに注意してください。このようにマークされたメンバーは、メソッドに違反せずにメソッドで変更できます。constconst契約に。

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


10

constメンバ関数の意味でのC ++共通知識:エッセンシャル中級プログラミングは明確な説明を与えます:

クラスXの非constメンバー関数のthisポインターの型はX * constです。つまり、それは非定数Xへの定数ポインターです(ConstポインターとConstへのポインター[7、21]を参照)。これが参照するオブジェクトはconstではないため、変更できます。クラスXのconstメンバー関数でのこの型は、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;
};

thisはありませんconst。変更できないのは、それが適切な値であるためです。
ブライアン

7

constメソッドシグネチャで使用する場合(前述のようにconst char* foo() const;)はthis、このメソッド(fooここにあります)によってポイントされたメモリは変更できないことをコンパイラに通知しています。


6

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

あなたも作ることができ 、それ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
}

答えを自由に改善してください。私は専門家ではありません


1
*thisメンバー関数が右辺値参照修飾されており、右辺値で呼び出された場合でも、常に左辺値です。
HolyBlackCat

1
はい、では、どうすれば現在の回答を改善できますか?
coder3101

ブロックにコメントを書いて、動作を正当化することを意味します
coder3101

更新しました。それは大丈夫ですか?
coder3101

2

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


1

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

「とはconstメンバー関数」ですか?

オブジェクトを検査する(変更するのではなく)メンバー関数。

constメンバ関数は、で示されるconstだけのメンバ関数のパラメータリストの後に接尾辞。const接尾辞付きのメンバー関数は、「constメンバー関数」または「インスペクター」と呼ばれます。constサフィックスのないメンバー関数は、「非constメンバー関数」または「ミューテーター」と呼ばれます。

class Fred {
public:
  void inspect() const;   // This member promises NOT to change *this
  void mutate();          // This member function might change *this
};
void userCode(Fred& changeable, const Fred& unchangeable)
{
  changeable.inspect();   // Okay: doesn't change a changeable object
  changeable.mutate();    // Okay: changes a changeable object
  unchangeable.inspect(); // Okay: doesn't change an unchangeable object
  unchangeable.mutate();  // ERROR: attempt to change unchangeable object
}

呼び出しの試みunchangeable.mutate()は、コンパイル時にキャッチされたエラーです。には実行時のスペースや速度のペナルティはなく、実行時constにチェックするためのテストケースを作成する必要はありません。

末尾constinspect()メンバ関数は、オブジェクトの変更されません方法を意味するために使用されるべき抽象(クライアントから見える)状態。これは、メソッドがオブジェクトの構造体の「生のビット」を変更しないと言うのとは少し異なります。C ++コンパイラーは、通常は解決できないエイリアシングの問題(つまり、オブジェクトの状態を変更する可能性のある非constエイリアスが存在する可能性がある)を解決できない限り、「ビット単位」の解釈を行うことはできません。このエイリアスの問題からの別の(重要な)洞察:constへのポインターでオブジェクトを指すことは、オブジェクトが変更されないことを保証しません。オブジェクトがそのポインタを介して変更されないこと約束するだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.