Static const variable is not constant in child class

早过忘川 提交于 2021-02-10 09:34:16

问题


I am using Visual Studio 2008 and have two classes Parent and Child. Parent declares some static const variables in the header, which are then defined in the cpp file. When I try to use the defines as cases in a switch statement in a child class I get the error: C2051: case expression not constant. So I've done some testing and the behavior I'm seeing is somewhat inconsistent.

// Parent.h
class Parent
{
public:
    Parent();
    ~Parent(void) { }

  static const unsigned long A = 1;
  static const unsigned long B;
};


// Parent.cpp
#include "Parent.h"

const unsigned long Parent::B = 2;

Parent::Parent()
{
  // Everything works fine here
  unsigned long l;
  switch(l)
  {
  case A:
    break;
  case B:
    break;
  default:
    break;
  }
}

// Child.h
#pragma once
#include "Parent.h"

class Child :
  public Parent
{
public:
  Child(void);
  virtual ~Child(void) { }

  static const int C = 3;
  static const int D;
};

// Child.cpp
#include "Child.h"

const int Child::D = 4;

Child::Child(void)
{
  unsigned long l;
  switch(l)
  {
  case A:
    break;
  case B:  // C2051: case expression not constant
    break;
  case C:
    break;
  case D:
    break;
  default:
    break;
  }
}

I've also tried specifying Parent::B directly, which doesn't solve the issue. Is there some reason why the expression is constant in all cases except when the variable is inherited from a parent class?


回答1:


You can only use a static const integer-type member variable in a constant expression if

  • it is initialized with a constant expression and
  • that constant expression is visible at the time that it is used.

In your switch, the value of Parent::A is visible because its initializer is in the Parent.h header file. The same goes for Child::C. The value of Child::D is visible because its initializer occurs earlier in Child.cpp.

However, the value of Parent::B is not visible: C++ source files are compiled separately, so when compiling Child.cpp, the compiler knows that Parent::B is a static const integer-type member variable, but it doesn't know what its value is. Thus, it can't be used in a constant expression in Child.cpp.


Note that if you ever use Parent::A as an object (e.g., &Parent::A), you will still need to define B in Parent.cpp, using const unsigned long Parent::A;, without an initializer, since you put the initializer in the class definition.




回答2:


I am surprised that Visual Studio let you get away with declaring the const outside of a class declaration. The line

static const unsigned long B;

inside your Parent class should not be allowed. When I tried your example on the Mac, which uses GNU g++ compiler, I got the following error:

error: declaration of 'const long unsigned int Parent::B' outside of class is not definition

As for why it works on one class, but not the other; my guess: inside the child.cpp file, the compiler saw that D was indeed declared as a const, but it has no knowledge of how B was defined (or redefined). To make this work, you should move all constant declarations to the class in the .h file and not .cpp file.




回答3:


The reason is that for the compiler the static const is not constant, beacuse at compile time it does not yet have a value, which is needed to compile the case statement.

The value is added later at link-time, when parent.o is linked to child.o (Remember that with plugins or shared libs link time could be as late as runtime).



来源:https://stackoverflow.com/questions/5421956/static-const-variable-is-not-constant-in-child-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!