问题
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