Что значит иметь неопределенную ссылку на статический член? - PullRequest
18 голосов
/ 17 августа 2011

Я только что написал класс с некоторыми статическими членами данных, но теперь я получаю ошибки о "неопределенных ссылках".Почему это не работает?Что я делаю не так?

(Примечание. Предполагается, что это будет вход в FAQ по C ++ Stack Overflow . Если вы хотите критиковать идею предоставленияFAQ в этой форме, тогда будет место для публикации мета, которая начала все это . Ответы на этот вопрос отслеживаются в C ++ chatroom , где начиналась идея FAQво-первых, поэтому ваш ответ, скорее всего, будет прочитан теми, кто придумал эту идею.)

Ответы [ 2 ]

26 голосов
/ 17 августа 2011

Чтобы понять это, вы должны хорошо понимать компиляцию и компоновку , а также различия между объявлениями и определениями .


Рассмотрим следующий класс:

//In header file
class Example {
    static bool exampleStaticMember;
};

Здесь exampleStaticMember объявлен, но не определен. Это означает, что если exampleStaticMember используется таким образом, что он должен иметь адрес, то для него должно быть отдельное определение. Как правило, ни одно объявление статического члена данных в определении класса не является определением этого члена.

Требуемое объявление обычно помещается в файл cpp, который содержит другие определения для членов класса. Он должен находиться в том же пространстве имен, что и определение класса. Определение обычно выглядит так:

//In source file:
//This may optionally have an initialiser (eg "= true")
bool Example::exampleStaticMember; 

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

В особом случае, если статическая переменная-член представляет собой константный интеграл или тип перечисления, тогда в определении класса может быть инициализатор:

//In header file
class Example {
    static const int initialised = 15;
};

В этом случае определение в файле cpp все еще требуется, но не разрешено иметь инициализатор:

//In source file
//Note: no initialiser!
const int Example::initialised;

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

Шаблоны

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

//In header file
template<typename T>
class Example {
    static int exampleInt;
    static T exampleT;
}
template<typename T> int Example<T>::exampleInt;
template<typename T> T Example<T>::exampleT;

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

Другое использование статического

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

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

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

5 голосов
/ 17 августа 2011

Вы должны создать экземпляры статических элементов, определенных в заголовке в файле .cpp. Например:

// foo.h

class foo {
    static int X;
};


// foo.cpp

#include "foo.h"

int foo::X = 0;
...