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


86

次の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データメンバーを変更できるのはなぜですか?


使用しているプラ​​ットフォームとコンパイラを教えていただければ助かりますか?そのため、動作が特定の設定に関連するバグであるかどうか、または動作が本当に正しく、説明が必要なだけであるかどうかを判断できます。
Alex Zywicki 2017年

Linuxプラットフォーム上の@ AlexZywickiG ++コンパイラ。
msc 2017年

8
必要なし。これは意図的なものであり、すべてのC ++コンパイラがサポートする必要があります。しかし、なぜこのような良い質問はもはや賛成されないのですか?
バトシェバ2017年

18
だまされていますが、MCVEが優れているので、他のものよりも書かれているので、これをターゲットとして使用しました。
Baum mitAugen

5
ここでの動機constは、オブジェクトのメンバー関数がその1つのオブジェクトを変更できないこと意味しますstaticクラスの特定のインスタンスではなく、クラスに関連付けられている同じクラスの他のオブジェクトまたはデータを変更できます。(またはmutable、このルールの例外として作成されたデータメンバー。)
Davislor 2017年

回答:


100

それがルールです、それだけです。そして、正当な理由があります。

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

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

したがって、最初のケースではa = 10;、の省略形と考えてくださいA::a = 10;。2番目のケースでは、の省略形と考えてください。this->a = 10;タイプがでthisあるため、コンパイルできませんconst A*


1
ここでのわずかなエラー:thisポインタを再割り当てできないため、の場合はタイプconst A* const になりますconst
テイラー

2
@TaylorHansenthisは、ポインタ型のprvalueです。非クラスタイプのPrvalueは、cv修飾されることはありません。

21

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

1静的データメンバーはクラスのサブオブジェクトの一部ではありません...

そして(9.2.2.1このポインタ)

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

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

3 ...名前ルックアップ(3.4)がid式の名前をあるクラスCの非静的非型メンバーに解決し、id式が潜在的に評価されるか、CがXまたは基本クラスである場合Xの場合、id式は、の左側の接尾辞式として(* this)(9.2.2.1)を使用して、クラスメンバーアクセス式(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データメンバーを変更するために定数ポインタを使用することはできません。また、関数は修飾子で宣言されているため、これが実際const A *に関数内で型を持っているポインター。この場合、関数に修飾子がない場合は、データメンバーを変更できます。setconst


13

ものは、あるクラスのメンバ関数があればそれAconst、その後のタイプthisでありconst X*、それによって変更されることから、非静的データメンバを防止する(例えば、CF、C ++標準):

9.3.2thisポインタ[class.this]

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

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

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


1

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

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