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

Linux 플랫폼의 @AlexZywicki G ++ 컴파일러.
msc

8
필요 없음. 의도적이며 모든 C ++ 컴파일러가이를 지원해야합니다. 그러나 이와 같은 좋은 질문이 더 이상 찬성되지 않는 이유는 무엇입니까?
밧세바

18
속임수이지만 더 나은 MCVE 덕분에 다른 것보다 더 잘 쓰여져 서 이것을 타겟으로 사용했습니다.
Baum mit Augen

5
여기서 동기 const는 객체의 멤버 함수가 해당 객체를 수정할 수 없음 을 의미 합니다 . 동일한 클래스의 다른 개체 또는 static클래스의 특정 인스턴스가 아닌 클래스와 연결된 데이터를 수정할 수 있습니다 . (또는 mutable이 규칙의 예외로 생성 된 데이터 멤버)
Davislor

답변:


100

그게 규칙입니다. 그리고 좋은 이유가 있습니다.

const멤버 함수 의 한정자는 클래스가 mutable아닌 static멤버 변수를 수정할 수 없음을 의미 합니다.

합리화를 제공하는 방식으로 정규화 된 멤버 함수 의 this포인터 constconst유형 this이며 본질적으로 클래스 의 인스턴스 와 관련됩니다 . static멤버는 클래스 인스턴스와 관련이 없습니다. static멤버 를 수정하는 데 인스턴스가 필요하지 않습니다 A::a = 10;. 귀하의 경우에는 .

따라서 첫 번째 경우에는의 a = 10;약자로 생각 A::a = 10;하고 두 번째 경우 this->a = 10;에는 유형이 this이므로 컴파일 할 수없는의 약자로 생각하십시오 const A*.


1
그냥 여기에 약간의 오류가 : 당신이 재 할당 할 수 없기 때문에 this포인터를,이 유형의 것 const A* const 에서 const의 경우.
Taylor Hansen은

2
@TaylorHansen this은 포인터 유형의 prvalue입니다. 비 클래스 유형의 Prvalue는 절대로 cv로 한정되지 않습니다.

21

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)을. 운영자.

따라서이 클래스 정의에서

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를 사용 하여 데이터 멤버를 수정할 수 없습니다 . 그리고 포인터 this는 실제로 함수가 한정자로 선언되기 때문에 const A *함수 내에서 유형을 set갖습니다 const. 이 경우 함수에 한정자가 없으면 데이터 멤버를 변경할 수 있습니다.


13

문제는 클래스의 멤버 함수 Aconst인 경우 유형이 this이므로 const X*비 정적 데이터 멤버가 변경되는 것을 방지합니다 (예 : C ++ 표준 ).

9.3.2 this 포인터 [class.this]

비 정적 (9.3) 멤버 함수의 본문에서 this 키워드는 해당 값이 함수가 호출되는 객체의 주소 인 prvalue 표현식입니다. 클래스 X의 멤버 함수에서 이것의 유형은 X *입니다. 멤버 함수가 const로 선언 된 경우이 유형은 const X *, ...

경우 a비 정적 데이터 부재는, 다음 a=10과 같이 동일한 this->a = 10유형이 경우 허용되지 않는, thisconst A*a선언되지 않았다 mutable. 따라서 void set() constthis존재 유형이므로이 const A*액세스는 허용되지 않습니다.

경우 a정적 데이터 멤버 인 반면, 다음 a=10이 포함되지 않는 this전혀; 오래 같이 static int a자체로 선언되지 않은 의한 const, 문이 a=10허용됩니다.


1

constA의 규정 멤버 함수 수정 할 수 없음을 의미 non-mutable, non-static 클래스 데이터 멤버 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.