web-dev-qa-db-ja.com

constメンバー関数が静的データメンバーを変更できるのはなぜですか?

以下では C++プログラムは、const関数から静的データメンバーを修正すると正常に動作します。

class A 
{
  public:   
    static int a; // static data member

    void set() const
    {
        a = 10;
    }
};

ただし、const関数から非静的データメンバーを変更しても機能しません。

class A 
{
  public:   
    int a; // non-static data member

    void set() const
    {
        a = 10;
    }
};

なぜconstメンバー関数がstaticデータメンバーを変更できるのですか?

81
msc

それがルールです、それがすべてです。そして、十分な理由があります。

メンバー関数のconst修飾子は、非mutablestaticクラスメンバー変数を変更できないことを意味します。

何らかの合理化を提供するために、this修飾メンバー関数のconstポインターはconst型であり、thisは本質的にクラスのインスタンスstaticメンバーは、クラスインスタンスに関連していません。 staticメンバーを変更するためにインスタンスは必要ありません:あなたの場合、A::a = 10;と書くことでそれを行うことができます。

したがって、最初のケースでは、a = 10;A::a = 10;の短縮形と考え、2番目のケースでは、this->a = 10;の短縮形と考えてください。これは、thisconst A*です。

94
Bathsheba

C++標準(9.2.3.2静的データメンバー)に準拠

1静的データメンバーはクラスのサブオブジェクトの一部ではない ...

そして(9.2.2.1 thisポインター)

1非静的(9.2.1)メンバー関数の本体では、キーワードthisは値が関数が呼び出されるオブジェクトのアドレスであるprvalue式です。クラスXのメンバー関数のこの型はX *です。 メンバー関数がconstとして宣言されている場合、この型はconst X *です、...

そして最後に(9.2.2非静的メンバー関数)

3 ...名前ルックアップ(3.4)がid-expressionの名前を何らかのクラスCの非静的非型メンバーに解決し、id-expressionが潜在的に評価されるか、CがXまたは基本クラスである場合Xの場合、id-expressionは、(* this)(9.2.2.1)を左側のpostfix-expressionとして使用して、クラスメンバーアクセス式(5.2.5)に変換されます。オペレーター。

したがって、このクラス定義では

class A 
{
  public:   
    static int a; 

    void set() const
    {
        a = 10;
    }
};

静的データメンバーaはクラス型のオブジェクトのサブオブジェクトではなく、ポインターthisは静的データメンバーへのアクセスには使用されません。したがって、非静的定数または非定数、または静的メンバー関数は、定数ではないため、データメンバーを変更できます。

このクラス定義では

class A 
{
  public:   
    int a; 

    void set() const
    {
        a = 10;
    }
};

非静的データメンバaは、クラスタイプのオブジェクトのサブオブジェクトです。メンバー関数でアクセスするには、この構文のメンバーアクセス構文が暗黙的に使用されます。定数ポインターthisを使用してデータメンバーを変更することはできません。関数は修飾子setで宣言されているため、これは実際、関数const内でconst A *型を持っています。この場合、関数に修飾子がない場合、データメンバーを変更できます。

21

問題は、クラスAのメンバー関数がconstである場合、thisの型はconst X*であるため、非静的データメンバーが変更されるのを防ぐことです。 (たとえば、 C++標準 を参照):

9.3.2 thisポインター[class.this]

非静的(9.3)メンバー関数の本文では、キーワードthisは、値が関数が呼び出されるオブジェクトのアドレスであるprvalue式です。クラスXのメンバー関数のこの型はX *です。メンバー関数がconstとして宣言されている場合、この型はconst X *、...

aが非静的データメンバーの場合、a=10this->a = 10と同じです。thisの型がconst A*であり、aが宣言されていない場合は許可されませんmutableとして。したがって、void set() constthisの型をconst A*にするため、このアクセスは許可されません。

対照的に、aが静的データメンバーである場合、a=10thisをまったく含みません。また、static int a自体がconstとして宣言されていない限り、ステートメントa=10は許可されます。

13
Stephan Lechner

メンバー関数const修飾子は、non-mutablenon-staticクラスデータメンバーを変更できないことを意味します。

1
Li Kui