Инициализировать статические переменные в классе C ++? - PullRequest
66 голосов
/ 16 февраля 2011

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

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

и так далее в классе.Затем я сделал их все static const, потому что они никогда не меняются.Однако моя программа компилируется, только если я перемещаю их из класса: в противном случае MSVC ++ 2010 жалуется на то, что «внутри класса могут быть инициализированы только статические интегральные переменные».Есть ли обходной путь?Я хотел бы оставить их в классе, к которому они принадлежат.

Ответы [ 9 ]

114 голосов
/ 16 февраля 2011

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

// 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 просто означает, что они не могут изменять никакие элементы, но все же могут иметь к ним доступ.

28 голосов
/ 16 февраля 2011

Майк Сеймур дал вам правильный ответ, но для добавления ...
C ++ позволяет объявлять и определять в теле вашего класса только статические константные целочисленные типы , как говорит компилятор.Таким образом, вы можете сделать:

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

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

15 голосов
/ 02 июля 2014

Начиная с C ++ 11 это можно сделать внутри класса с constexpr.

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

Теперь к переменной можно получить доступ:

stat::inlineStaticVar
15 голосов
/ 16 февраля 2011

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

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


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

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

9 голосов
/ 16 февраля 2011

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

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

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 голосов
/ 01 июля 2015

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

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

// 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();
2 голосов
/ 11 февраля 2015

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

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

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

1 голос
/ 11 июня 2015

Опционально, переместите все свои константы в файл .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;
}
0 голосов
/ 11 мая 2018

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

Вам не нужно

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

#ifndef CLASS_A_H
#define CLASS_A_H
#include <string>
class A
{
private:
    static std::string str;
    static int x;
};
// Initialize with no values
std::string A::str;
int A::x;
// Initialize with values
//std::string A::str = "SO!";
//int A::x = 900;
#endif
...