Подтвердить что ты не робот

Инициализировать статические переменные в классе C++?

Я заметил, что некоторые из моих функций в классе фактически не обращаются к объекту, поэтому я сделал их static. Затем компилятор сказал мне, что все переменные, к которым они обращаются, также должны быть статичными - и это вполне понятно. У меня есть куча строковых переменных, таких как

string RE_ANY = "([^\\n]*)";
string RE_ANY_RELUCTANT = "([^\\n]*?)";

и т.д. в классе. Затем я сделал их всех static const, потому что они никогда не меняются. Однако моя программа компилируется только в том случае, если я вывожу их из класса: иначе MSVС++ 2010 жалуется: "Только статические постоянные интегральные переменные могут быть инициализированы внутри класса".

Что ж, это несчастливо. Есть ли обходной путь? Я хотел бы оставить их внутри класса, к которому они принадлежат.

4b9b3361

Ответ 1

Они не могут быть инициализированы внутри класса, но они могут быть инициализированы вне класса в исходном файле:

// inside the class
class Thing {
    static string RE_ANY;
    static string RE_ANY_RELUCTANT;
};

// in the source file
string Thing::RE_ANY = "([^\\n]*)";
string Thing::RE_ANY_RELUCTANT = "([^\\n]*?)";

Обновление

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

Ответ 2

Майк Сеймур дал вам правильный ответ, но добавить...
С++ позволяет объявлять и определять в вашем классе тела только static const integer, как сообщает компилятор. Итак, вы действительно можете:

class Foo
{
    static const int someInt = 1;
    static const short someShort = 2;
    // etc.
};

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

Ответ 3

Статические переменные-члены должны быть объявлены в классе, а затем определены вне его!

Нет обходного пути, просто поместите свое фактическое определение в исходный файл.


Из вашего описания пахнет, что вы не используете статические переменные правильно. Если они никогда не меняются, вы должны использовать постоянную переменную, но ваше описание слишком общее, чтобы сказать что-то еще.

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

Ответ 4

Так как С++ 11 можно сделать внутри класса с constexpr.

class stat {
    public:
        // init inside class
        static constexpr double inlineStaticVar = 22;
};

Теперь переменную можно получить с помощью:

stat::inlineStaticVar

Ответ 5

Я считаю, что стоит добавить, что статическая переменная не совпадает с постоянной переменной.

с использованием постоянной переменной в классе

struct Foo{
    const int a;
    Foo(int b) : a(b){}
}

и мы объявим его так, как будто

fooA = new Foo(5);
fooB = new Foo(10);
// fooA.a = 5;
// fooB.a = 10;

Для статической переменной

struct Bar{
    static int a;
    Foo(int b){
        a = b;
    }
}
Bar::a = 0; // set value for a

который используется так

barA = new Bar(5);
barB = new Bar(10);
// barA.a = 10;
// barB.a = 10;
// Bar::a = 10;

Вы видите, что здесь происходит. Постоянная переменная, которая инициализируется вместе с каждым экземпляром Foo, поскольку Foo имеет значение, имеет отдельное значение для каждого экземпляра Foo и не может быть вообще изменена Foo.

Где, как и в случае с Bar, это только одно значение для Bar:: независимо от количества экземпляров Bar. Все они разделяют эту ценность, вы также можете получить к ней доступ, поскольку они являются экземплярами Bar. Статическая переменная также поддерживает правила для public/private, поэтому вы можете сделать так, чтобы только экземпляры Bar могли считывать значение Bar:: a;

Ответ 6

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

Объявите свой статический член как обычно.

// myClass.h
class myClass
{
static complexClass s_complex;
//...
};

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

//class.cpp    
#include myClass.h
complexClass initFunction()
{
    complexClass c;
    c.add(...);
    c.compute(...);
    c.sort(...);
    // Etc.
    return c;
}

complexClass myClass::s_complex = initFunction();

Ответ 7

Если ваша цель - инициализировать статическую переменную в вашем файле заголовка (вместо файла *.cpp, который вам может понадобиться, если вы придерживаетесь идиомы "только заголовка" ), тогда вы можете обойти проблему инициализации используя шаблон. Шаблонные статические переменные могут быть инициализированы в заголовке, не вызывая определения нескольких символов.

См. здесь пример:

Статическая инициализация члена в шаблоне класса

Ответ 8

При необходимости переместите все свои константы в файл .cpp без объявления в файле .h. Используйте анонимное пространство имен, чтобы сделать их невидимыми за пределами модуля cpp.

// MyClass.cpp

#include "MyClass.h"

// anonymous namespace
namespace
{
    string RE_ANY = "([^\\n]*)";
    string RE_ANY_RELUCTANT = "([^\\n]*?)";
}

// member function (static or not)
bool MyClass::foo()
{
    // logic that uses constants
    return RE_ANY_RELUCTANT.size() > 0;
}

Ответ 9

Некоторые ответы кажутся немного вводящими в заблуждение.

Вам не нужно...

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

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


Инициализировать без значений в одном файле

#include <string>
class A
{
    static std::string str;
    static int x;
};
std::string A::str;
int A::x;

Инициализация со значениями в том же файле

#include <string>
class A
{
    static std::string str;
    static int x;
};
std::string A::str = "SO!";
int A::x = 900;

Инициализируйте в той же области видимости класса, используя ключевое слово inline

#include <string>
class A
{
    static inline std::string str = "SO!";
    static inline int x = 900;
};