开发者

Static const variable is not constant in child class

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开发者_Python百科 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?


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.


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.


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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜