статическая переменная-член внутри локального класса в С++?

Я знаю, что мы не можем объявить переменную-член static внутри локального класса... но причина этого не ясна.

Итак, пожалуйста, кто-нибудь может объяснить это?

Кроме того, почему мы не можем получить доступ к переменной, отличной от static, определенной внутри функции, в которой был определен локальный класс, непосредственно в функциях-членах локального класса?

В приведенном ниже коде:

int main(int argc, char *argv[])
{
    static size_t staticValue = 0;

    class Local
    {
         int d_argc; // non-static data members OK
         public:
         enum // enums OK
         {
             value = 5
         };
         Local(int argc) // constructors and member functions OK
         : // in-class implementation required
          d_argc(argc)
         {
               // global data: accessible
               cout << "Local constructor\n";
               // static function variables: accessible
               staticValue += 5;
         }
         static void hello() // static member functions: OK
         { 
            cout << "hello world\n";
         }
   };
   Local::hello(); // call Local static member
   Local loc(argc); // define object of a local class.
   return 0;
}

Статическая переменная staticValue доступна напрямую, в то время как, с другой стороны, аргумент argc из main не доступен....


person ishan    schedule 06.01.2010    source источник
comment
я не понял что ты имеешь в виду? что вы хотите сделать в своей локальной функции класса? можешь привести пример?   -  person ufukgun    schedule 06.01.2010
comment
Мы не можем точно сказать, что вы спрашиваете, без примера кода, ваш вопрос не ясен.   -  person bmargulies    schedule 06.01.2010
comment
Я никогда не видел, чтобы местные классы использовались. Не могу я придумать ни одной ситуации, в которой они были бы полезным инструментом.   -  person James    schedule 06.01.2010


Ответы (6)


Два вопроса связаны. Я полагаю, что ответ вам не ясен, потому что ключевое слово static в C++ имеет перегруженные значения.

Когда вы определяете статическую переменную внутри функции, вы на самом деле говорите компилятору инициализировать ее только при первом вызове (чтобы вы могли использовать значение при нескольких вызовах). Это не совсем то же самое, что и в случае статической переменной области файла или области класса.

Имея это в виду, может не иметь смысла определять статическую переменную внутри локального класса, который, в свою очередь, определяется внутри функции.

Что касается вашего второго вопроса, локальный класс на самом деле может получить доступ к статическим переменным, определенным в его закрывающей функции. Приведенный ниже код, например, должен компилироваться в компиляторе, совместимом со стандартами.


void f()
{
  static int i;
  class local
  {
    int g() { return i; }
  };

  local l;
  /* ... */
}

int main()
{
  f();
  return 0;
}
person Leandro T. C. Melo    schedule 06.01.2010
comment
Я неправильно сформулировал вопрос, извините за это. я хотел спросить о нестатическом члене, который не доступен напрямую внутри локального класса - person ishan; 06.01.2010

Локальные классы не имеют полного доступа к своей среде (спасибо, Ричард)... вам нужно использовать, например. ссылки или указатели, чтобы обойти это:

void f() {
    int i = 0;

    struct local {
        int& i;
        local(int& i) : i(i) {}
        void f() { i = 1; }
    };

    local l(i);
    l.f();
    assert(i==1);
}
person Georg Fritzsche    schedule 06.01.2010
comment
Локальные классы имеют доступ к статическим переменным в функции. Вам не нужна ссылка. - person Richard Pennington; 06.01.2010
comment
Спасибо, почему-то я этого не понял. - person Georg Fritzsche; 06.01.2010

Другая причина, по которой вы не можете исследовать переменные стека в объемлющей области, заключается в том, что функция в локальном классе не обязательно вызывается непосредственно из объемлющей функции.

В приведенном ниже примере жизнь была бы проще, если бы hello() была единственной функцией в классе: чтобы найти переменную stackValue, hello() нужно было бы просто заглянуть во фрейм стека вызывающего объекта. Но здесь я представил Local::goodbye(), который может вызывать или не вызывать Local::hello. В этом случае, как Local::hello() узнать, где найти кадр стека закрывающей функции? (Для этого нам понадобятся замыкания. Мне нравятся замыкания, но я не вижу, чтобы это происходило в C++.)

int main(int argc, char *argv[])
{
    static size_t staticValue = 0;
    int size_t stackValue = argc;

    class Local
    {
         void hello() 
         { 
            cout << "stackValue is " << stackValue << "\n";
         }
         void goodbye()
         {
            if (stackValue == 42) {
                hello();
            }
            else {
                cout << "Goodbye!\n";
            }
         }
   };
   Local loc;
   loc.hello();
   stackValue = 42;
   loc.goodbye();
   return 0;
}
person Dan Breslau    schedule 06.01.2010

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

Согласно Википедии

В компьютерном программировании статическая переменная — это переменная, которая была выделена статически, время жизни которой распространяется на весь запуск программы.

Это отличается от загрузки и выгрузки локальных классов с объявленными статическими переменными.

person Xinus    schedule 06.01.2010

Я думаю, что причина того, что локальные классы не могут иметь статических членов (или функций, определенных вне класса), больше связана с синтаксисом, чем семантикой. Статические члены могут быть реализованы так же, как и в нелокальных классах: статические будут иметь время жизни, начинающееся с первого вызова функции, как и статические переменные, объявленные внутри функции. Компилятор должен убедиться, что статические члены были инициализированы при создании первого экземпляра класса.

Представьте себе проблему с искажением имени теперь, когда сигнатура закрывающей функции становится частью имени. ;-)

Причина, по которой вы не можете получить доступ к локальным переменным или параметрам функции в локальном классе, заключается в том, что это усложнит код, необходимый для реализации класса с небольшим выигрышем. Доступ к нестатическим членам класса обычно осуществляется через указатель this или указатель на конкретный экземпляр. Для доступа к переменным и параметрам, локальным для объемлющей функции, потребуется некоторый механизм, делающий их доступными. Этот механизм мог бы быть довольно тривиальным, если бы функции были встроенными, но что произойдет, если это не так?

person Richard Pennington    schedule 06.01.2010
comment
@Dan: я согласен с доступом к локальной переменной (см. мой третий абзац), я говорил о локальных статических членах. - person Richard Pennington; 06.01.2010

person    schedule
comment
Локальные объекты могут быть определены в теле функции, но они не могут покидать функцию как объекты своего собственного типа. То есть имя локального класса нельзя использовать ни для возвращаемого типа, ни для типов параметров окружающих его функций. Однако в качестве прелюдии к наследованию локальный класс может быть получен из существующего класса, позволяя окружающей функции возвращать динамически размещенный объект класса, созданный локально, указатель или ссылка могут быть возвращены через указатель или ссылку базового класса. - person ishan; 07.01.2010