静态const变量在子类中不是常量

时间:2011-03-24 15:56:17

标签: c++ inheritance visual-c++-2008

我正在使用Visual Studio 2008并且有两个类Parent和Child。 Parent在头文件中声明了一些静态const变量,然后在cpp文件中定义。当我尝试在子类的switch语句中使用define作为案例时,我得到错误: C2051:case expression not constant 。所以我做了一些测试,我看到的行为有些不一致。

// 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;
  }
}

我也尝试过直接指定Parent::B,但这并没有解决问题。除非从父类继承变量,否则表达式在所有情况下都是常量?

3 个答案:

答案 0 :(得分:7)

如果

,则只能在常量表达式中使用static const整数类型的成员变量
  • 使用常量表达式初始化
  • 常量表达式在使用时可见。

switch中,Parent::A的值是可见的,因为它的初始化程序位于Parent.h头文件中。 Child::C也是如此。 Child::D的值是可见的,因为它的初始化程序在Child.cpp中较早出现。

但是,Parent::B的值不可见:C ++源文件是单独编译的,因此在编译Child.cpp时,编译器知道Parent::Bstatic const整数类型成员变量,但它不知道它的值是什么。因此,它不能用于Child.cpp中的常量表达式。


请注意,如果您使用Parent::A作为对象(例如&Parent::A),则仍需要使用B在Parent.cpp中定义const unsigned long Parent::A;,没有初始化程序,因为你把初始化程序放在类定义中。

答案 1 :(得分:0)

我很惊讶Visual Studio允许您在类声明之外声明const。这条线

static const unsigned long B;
不应允许在父类中使用

。当我在使用GNU g ++编译器的Mac上尝试你的例子时,我收到了以下错误:

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

至于为什么它适用于一个类,而不是另一个类;我的猜测:在child.cpp文件中,编译器看到D确实被声明为const,但它不知道B是如何定义(或重新定义)的。要使其工作,您应该将所有常量声明移动到.h文件中的类而不是.cpp文件中。

答案 2 :(得分:0)

原因是编译器static const不是常量,因为在编译时它还没有一个值,这是编译case语句所需要的。

parent.o链接到child.o时,会在链接时添加该值(请记住,对于插件或共享库,链接时间可能晚于运行时)。