为什么常量成员函数可以修改静态数据成员?

在下面的 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数据成员?

10151 次浏览

It's the rule, that's all. And for good reason.

The const qualifier on a member function means that you cannot modify non-mutable non-static class member variables.

By way of offering some rationalisation, the this pointer in a const qualified member function is a const type, and this is inherently related to an instance of a class. static members are not related to a class instance. You don't need an instance to modify a static member: you can do it, in your case, by writing A::a = 10;.

So, in your first case, think of a = 10; as shorthand for A::a = 10; and in the second case, think of it as shorthand for this->a = 10;, which is not compilable since the type of this is const A*.

The thing is, that if a member function of a class A is const, then the type of this is const X*, and thereby prevents non-static data members from being altered (cf, for example, C++ standard):

9.3.2 The this pointer [class.this]

In the body of a non-static (9.3) member function, the keyword this is a prvalue expression whose value is the address of the object for which the function is called. The type of this in a member function of a class X is X*. If the member function is declared const, the type of this is const X*, ...

If a is a non-static data member, then a=10 is the same as this->a = 10, which is not allowed if the type of this is const A* and a has not been declared as mutable. Thus, since void set() const makes the type of this being const A*, this access is not allowed.

If a is a static data member, in contrast, then a=10 does not involve this at all; and as long as static int a by itself has not been declared as const, statement a=10 is allowed.

According to the C++ Standard (9.2.3.2 Static data members)

1 A static data member is not part of the subobjects of a class...

And (9.2.2.1 The this pointer)

1 In the body of a non-static (9.2.1) member function, the keyword this is a prvalue expression whose value is the address of the object for which the function is called. The type of this in a member function of a class X is X*. If the member function is declared const, the type of this is const X*,...

And at last (9.2.2 Non-static member functions)

3 ... if name lookup (3.4) resolves the name in the id-expression to a non-static non-type member of some class C, and if either the id-expression is potentially evaluated or C is X or a base class of X, the id-expression is transformed into a class member access expression (5.2.5) using (*this) (9.2.2.1) as the postfix-expression to the left of the . operator.

Thus in this class definition

class A
{
public:
static int a;


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

the static data member a is not a subobject of an object of the class type and the pointer this is not used to access the static data member. So any member function, non-static constant or non-constant, or a static member function can change the data member because it is not a constant.

In this class definition

class A
{
public:
int a;


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

the non-static data member a is an subobject of an object of the class type. To access it in a member function there is used either a member access syntax of this syntax is implied. You may not use a constant pointer this to modify the data member. And the pointer this is indeed has type const A * within the function set because the function is declared with the qualifier const. If the function had no the qualifier in this case the data member could be changed.

The const qualifier on a member function means that you cannot modify non-mutable, non-static class data members.