Я хочу иметь класс с закрытым статическим членом данных (вектор, который содержит все символы az). В Java или C # я могу просто создать «статический конструктор», который будет запускаться до того, как я создам экземпляры класса, и установить статические члены-данные класса. Он запускается только один раз (поскольку переменные доступны только для чтения и должны быть установлены только один раз), и поскольку он является функцией класса, он может получить доступ к своим закрытым членам. Я мог бы добавить код в конструктор, который проверяет, инициализирован ли вектор, и инициализировать его, если это не так, но это вводит много необходимых проверок и не кажется оптимальным решением проблемы.
Мне приходит в голову мысль, что, поскольку переменные будут доступны только для чтения, они могут быть просто открытыми статическими константами, поэтому я могу установить их один раз за пределы класса, но, опять же, это выглядит как уродливый хак.
Можно ли иметь частные статические члены-данные в классе, если я не хочу инициализировать их в конструкторе экземпляра?
источник
Ответы:
Чтобы получить эквивалент статического конструктора, вам нужно написать отдельный обычный класс для хранения статических данных, а затем создать статический экземпляр этого обычного класса.
источник
friend
имеет большой смысл, так что классElsewhere
может легко получить доступStaticStuff
к внутренним объектам (не нарушая инкапсуляцию каким-либо опасным способом, я мог бы добавить).Ну, вы можете иметь
Не забудьте (в .cpp) это:
Программа по-прежнему будет ссылаться без второй строки, но инициализатор не будет выполнен.
источник
MyClass::a.push_back(i)
вместоa.push_back(i)
?_initializer
является подобъектомMyClass
. Субобъекты инициализируются в следующем порядке: виртуальные субобъекты базового класса, в порядке глубины, слева направо (но инициализируют каждый отдельный подобъект только один раз); затем подобъекты простого базового класса в порядке глубины слева направо; затем член подобъектов в порядке объявления. Таким образом, безопасно использовать стратегию EFraim, при условии, что код_initialiser
относится только к членам, объявленным до него.Решение C ++ 11
Начиная с C ++ 11, вы можете просто использовать лямбда-выражения для инициализации статических членов класса. Это даже работает, если вам нужно наложить порядок построения между различными статическими элементами, или если у вас есть статические элементы, которые есть
const
.Заголовочный файл:
Исходный файл:
источник
try catch
блок, если могут быть сгенерированы исключения.В файле .h:
В файле .cpp:
источник
Вот еще один подход, аналогичный Даниэлю Эрвикеру, также использующий предложение класса от друга Конрада Рудольфа. Здесь мы используем внутренний приватный служебный класс друга для инициализации статических членов вашего основного класса. Например:
Заголовочный файл:
Файл реализации:
Преимущество этого подхода состоит в том, что он полностью скрывает класс Initializer от внешнего мира, сохраняя все содержимое этого класса для инициализации.
источник
ToBeInitialized::Initializer::Initializer()
вызывается, поэтому вам нужно добавитьToBeInitialized::Initializer ToBeInitialized::initializer;
его в файл реализации. Я взял кое-что из твоей идеи и идеи Эфрейма, и это работает именно так, как мне нужно, и выглядит чисто. Спасибо чувак.Test::StaticTest()
вызывается ровно один раз при глобальной статической инициализации.Вызывающая сторона должна добавить только одну строку в функцию, которая должна быть их статическим конструктором.
static_constructor<&Test::StaticTest>::c;
вызывает инициализациюc
во время глобальной статической инициализации.источник
Нет необходимости в
init()
функции,std::vector
может быть создан из диапазона:Обратите внимание, однако, что статика типа класса вызывает проблемы в библиотеках, поэтому их следует избегать.
C ++ 11 Обновление
Начиная с C ++ 11, вы можете сделать это вместо этого:
Это семантически эквивалентно решению C ++ 98 в исходном ответе, но вы не можете использовать строковый литерал справа, поэтому он не является полностью превосходящим. Однако, если у Вас есть вектор любого другого типа , чем
char
,wchar_t
,char16_t
илиchar32_t
(массивы из которых может быть записаны в виде строковых литералов), версия C ++ 11 будет строго удалить шаблонный код без введения другого синтаксиса, по сравнению с C ++ 98 версия.источник
Концепция статических конструкторов была введена в Java после того, как они извлекли уроки из проблем в C ++. Так что у нас нет прямого эквивалента.
Лучшее решение - использовать типы POD, которые могут быть инициализированы явно.
Или сделайте ваши статические члены определенным типом, который имеет свой собственный конструктор, который будет правильно инициализировать его.
источник
При попытке скомпилировать и использовать класс
Elsewhere
(из ответа Уорикера ) я получаю:Кажется, невозможно инициализировать статические атрибуты нецелых типов, не помещая некоторый код вне определения класса (CPP).
Для компиляции вы можете использовать « статический метод со статической локальной переменной внутри ». Что-то вроде этого:
И вы также можете передавать аргументы в конструктор или инициализировать его конкретными значениями, это очень гибкий, мощный и простой в реализации ... единственное, что у вас есть статический метод, содержащий статическую переменную, а не статический атрибут ... синтаксис немного меняется, но все же полезен. Надеюсь, это кому-нибудь пригодится,
Уго Гонсалес Кастро.
источник
Я думаю, простое решение этого будет:
источник
Просто решил тот же трюк. Мне пришлось указать определение одного статического члена для Singleton. Но все усложняется - я решил, что не хочу вызывать ctor из RandClass (), если только не собираюсь его использовать ... вот почему я не хотел глобально инициализировать синглтон в моем коде. Также я добавил простой интерфейс в моем случае.
Вот окончательный код:
Я упростил код и использовал функцию rand () и ее инициализатор с одиночным семенем srand ()
источник
Вот мой вариант решения EFraim; Разница в том, что благодаря неявной реализации шаблона статический конструктор вызывается только в том случае, если создаются экземпляры класса, и что определение в
.cpp
файле не требуется (благодаря магии создания шаблона).В
.h
файле у вас есть:В
.cpp
файле вы можете иметь:Обратите внимание, что
MyClass::a
он инициализируется, только если есть строка [1], потому что это вызывает (и требует создания экземпляра) конструктор, который затем требует создания экземпляра_initializer
.источник
Вот еще один метод, где вектор является закрытым для файла, который содержит реализацию, используя анонимное пространство имен. Это полезно для таких вещей, как таблицы поиска, которые являются частными для реализации:
источник
I
иi
что - то немного более неясными , чтобы вы случайно не использовать их где - то ниже в файле.Это, конечно, не должно быть таким сложным, как принятый в настоящее время ответ (Дэниел Эрвикер). Класс лишний. В этом случае нет необходимости в языковой войне.
Файл .hpp:
Файл .cpp:
источник
GCC предлагает
https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
Пометьте статический метод этим атрибутом, и он будет запускаться при загрузке модуля перед main ().
источник
Вы определяете статические переменные-члены аналогично тому, как вы определяете методы-члены.
foo.h
foo.cpp
источник
Чтобы инициализировать статическую переменную, вы просто делаете это внутри исходного файла. Например:
источник
Как насчет создания шаблона для имитации поведения C #.
источник
Для простых случаев, таких как здесь, статическая переменная, заключенная в статическую функцию-член, почти так же хороша. Это просто и обычно оптимизируется компиляторами. Это не решает проблему порядка инициализации для сложных объектов.
источник
Это решение?
источник
Статический конструктор можно эмулировать, используя класс друга или вложенный класс, как показано ниже.
Вывод:
источник
new
используете массив символов только для того, чтобы немедленно утечь указатель и перезаписать его?Ничего себе, я не могу поверить, что никто не упомянул самый очевидный ответ, и тот, который наиболее близко имитирует поведение статического конструктора C #, то есть он не вызывается, пока не будет создан первый объект этого типа.
std::call_once()
доступен в C ++ 11; если вы не можете использовать это, это можно сделать с помощью статической логической переменной класса и атомарной операции сравнения и обмена. В своем конструкторе посмотрите, можете ли вы атомарно изменить флаг класса-статики сfalse
наtrue
, и если это так, вы можете запустить код статической конструкции.Для дополнительного кредита, сделайте его трехсторонним флагом вместо логического, то есть не запускать, запускать и завершить запуск. Затем все другие экземпляры этого класса могут вращаться до тех пор, пока экземпляр, выполняющий статический конструктор, не завершит работу (т. Е. Выдаст забор памяти, а затем установит состояние «завершено»). Ваша спин-блокировка должна выполнять команду «паузы» процессора, удваивать время ожидания каждый раз до порога и т. Д. - довольно стандартная техника спин-блокировки.
В отсутствие C ++ 11 это должно помочь вам начать.
Вот какой-то псевдокод, который поможет вам. Поместите это в определение вашего класса:
И это в вашем конструкторе:
источник