为什么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 '17年

@AlexZywicki Linux平台上的G ++编译器。
msc

8
没必要。这是有意的,所有C ++编译器都必须支持它。但是,为什么像这样的好问题不再受到支持?
芭丝谢芭

18
这是一个骗子,但由于拥有更好的MCVE,它的书写效果比另一个更好,因此我将其用作目标。
鲍姆·米特·奥根

5
这里的动机是const意味着对象的成员函数不能修改该对象。它可以修改与该类static关联的同一类或数据的其他对象,而不是该类的任何特定实例。(或者mutable创建的数据成员是该规则的例外。)
Davislor

Answers:


100

这就是规则,仅此而已。并且有充分的理由。

const成员函数上的限定符意味着您不能修改mutable非非static类成员变量。

通过提供某种合理化的方式,合格成员函数中的this指针const是一种const类型,并且this与类的实例固有地相关。static成员与类实例无关。您不需要实例来修改static成员:您可以通过编写来实现A::a = 10;

因此,在您的第一种情况下,应将其a = 10;视为的简写,A::a = 10;而在第二种情况下,this->a = 10;应将其视为的简写,这是不可编译的,因为的类型thisconst A*


1
这里只是一个小错误:由于您无法重新分配this指针,因此它的类型const A* constconst
泰勒·汉森

2
@TaylorHansenthis是指针类型的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表达式中的名称解析为某个类C的非静态非类型成员,并且如果id表达式可能被求值或者C为X或基类X的id表达式使用(* 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来修改数据成员。而且指针确实const A *在函数中具有类型,set因为该函数是用限定符声明的const。如果在这种情况下该函数没有限定符,则可以更改数据成员。


13

事实是,如果类的成员函数Aconst,则类型thisconst X*,从而防止更改非静态数据成员(例如,参见C ++ standard):

9.3.2 this指针[class.this]

在非静态(9.3)成员函数的主体中,关键字this是一个prvalue表达式,其值是为其调用该函数的对象的地址。在类X的成员函数中,此类型为X *。如果将成员函数声明为const,则其类型为const X *,...

如果a是非静态数据成员,则a=10与相同this->a = 10,如果thisis的类型const A*a尚未声明为,则不允许使用mutable。因此,由于void set() const类型为thisbeing const A*,因此不允许该访问。

a相反,如果是静态数据成员,则a=10根本不涉及this;并且只要static int a它本身没有被声明为consta=10就允许使用该语句。


1

const上一个限定成员函数意味着你不能修改non-mutablenon-static 类的数据成员

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.