Статическая константная переменная не является постоянной в дочернем классе - PullRequest
2 голосов
/ 24 марта 2011

Я использую Visual Studio 2008 и у меня есть два класса Parent и Child.Родитель объявляет некоторые статические константные переменные в заголовке, которые затем определяются в файле cpp.Когда я пытаюсь использовать определения в качестве наблюдений в операторе switch дочернего класса, я получаю сообщение об ошибке: C2051: регистр выражений не является константой .Итак, я провел некоторое тестирование, и поведение, которое я вижу, несколько противоречиво.

// 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 ]

7 голосов
/ 24 марта 2011

Вы можете использовать static const переменную-член целочисленного типа в константном выражении, только если

  • инициализировано с константным выражением и
  • , что константное выражение видновремя его использования.

В вашем switch значение Parent::A видно, потому что его инициализатор находится в заголовочном файле Parent.h.То же самое касается Child::C.Значение Child::D видно, потому что его инициализатор встречается раньше в Child.cpp.

Однако значение Parent::B не отображается: исходные файлы C ++ компилируются отдельно, поэтому при компиляции Child.cpp,компилятор знает, что Parent::B является static const переменной-членом целочисленного типа, но он не знает, каково ее значение.Таким образом, его нельзя использовать в константном выражении в Child.cpp.


Обратите внимание, что если вы когда-либо используете Parent::A в качестве объекта (например, &Parent::A), вам все равно понадобитсяопределить B в Parent.cpp, используя const unsigned long Parent::A;, без инициализатора, поскольку вы помещаете инициализатор в определение класса.

0 голосов
/ 24 марта 2011

Причина в том, что для компилятора static const не является константой, поскольку во время компиляции у него еще нет значения, которое необходимо для компиляции оператора case.

Значение добавляется позже во время компоновки, когда parent.o связано с child.o (помните, что с плагинами или общими библиотеками время ссылки может быть уже во время выполнения).

0 голосов
/ 24 марта 2011

Я удивлен, что Visual Studio позволяет вам объявлять const вне объявления класса. Линия

static const unsigned long B;

внутри вашего родительского класса не должно быть разрешено. Когда я попробовал ваш пример на Mac, который использует компилятор GNU g ++, я получил следующую ошибку:

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

Что касается того, почему он работает в одном классе, а не в другом; мое предположение: внутри файла child.cpp компилятор увидел, что D действительно объявлен как const, но он не знает, как был определен (или переопределен) B. Чтобы это работало, вы должны переместить все объявления констант в класс в файле .h, а не в файле .cpp.

...