Поскольку инициализация C++ через TU - это большая серая область с большим объемом реализации, я предпочитаю полностью ее обрывать и четко указывать, что делается, когда. (Это отклонение порядка инициализации из-за отсутствия гарантий аналогично тому, как singleton classes отклоняет глобальные объекты.) В частности, это означает любое глобальное состояние (глобальные переменные, статические члены данных и функция-локальная статика), которые не могут быть инициализированы постоянными выражениями должен быть инициализирован точно в одном ТУ, и что ТУ является тем, который реализует основной.
В ручном случае, это означает, что вставки и обновления кода в ЕП, который содержит главный и в самой основной. Наиболее распространенным примером такого кода является вызов srand(time(0))
для посева std :: rand PRNG.
Вы можете реорганизовать, что ручное управление кодом с помощью препроцессора:
// the implementation file for main, could be named main.cpp
#include "whatever_declares_the_real_main.hpp"
#include "global_objects.inc"
int main(int argc, char* argv[]) try {
#include "main_init.inc"
return the_real_main(argc, argv);
// main.cpp has well-defined responsibility:
// initialize global state before passing control to another function, and
// handle return-code or exceptions
// you can modify this, depending on your preference and desired API
// for example:
return the_real_main(std::vector<std::string>(argv+1, argv+argc));
return the_real_main(parse_args(argv+1, argv+argc));
// just make sure to keep main.cpp's responsibility well-defined and
// relatively simple
}
// example handling; depending on your specifics, you might do something
// different, or know how to provide more information:
catch (std::exception& e) {
std::cerr << "abnormal termination: " << e.what() << '\n';
return 1;
}
catch (...) {
std::cerr << "abnormal termination.\n";
return 1;
}
Эти .INC файлы не являются ни заголовки, ни файлы реализации. Точное расширение файла не имеет значения, если вы не используете что-то, что обычно используется для заголовков или файлов реализации, таких как .h, .hpp, .cc, .cpp и т. Д. Вы можете генерировать global_objects.inc и main_init.inc основываются на соглашениях об именах файлов, используя включенные охранники, чтобы можно было включить зависимости (так же, как включение охранников для заголовков).
Например, оба этих файла соответствуют myevent.HPP и будет размещен рядом с этим заголовком:
// file "myevent.global_inc"
#ifndef INCLUDE_GUARD_37E6F5857F8F47918A7C83F29A9DA868
#define INCLUDE_GUARD_37E6F5857F8F47918A7C83F29A9DA868
#include <QEvent.hpp> // or whatever headers you need
#include "myevent.hpp" // declares the variable defined just below
// (remember you use 'extern' to declare objects without defining them)
int your_namespace::myEventType = QEvent::registerEventType();
#endif
// file "myevent.main_inc"
#ifndef INCLUDE_GUARD_4F1B93D0F4D3402B802CBA433241AA81
#define INCLUDE_GUARD_4F1B93D0F4D3402B802CBA433241AA81
// nothing needed in this case, from what you've shown so far
// this is where you place expressions that would otherwise require a dummy
// global variable to make sure they are executed, but this also allows use
// of temporary variables while includes handle dependency order:
#include "something_else.main_inc" // fake example dependency, which must
{ // be executed first
int temp;
some_func(&temp);
other_func(temp); // not easy to transform this into a global's init
// expression, yet defining it this way is natural, because it's exactly
// how you would do it inside a function
}
#endif
Обратите внимание, что если требуется только статическая инициализация данных с постоянными выражениями, то, что предпочтительнее, чем все другие методами. Основное ограничение для этой инициализации не позволяет выполнить вызов функции (но это на самом деле более сложный), поэтому он не применяется в вашем случае; это единственный тип инициализации глобальной переменной, который может выполнять C, если вы хотите узнать больше.
Думая об этом, я понимаю, что я мог бы, вероятно, просто назвать QEvent :: registerEventType() в конструкторе моего объекта MyEvent следующим образом: MyEvent :: MyEvent(): QEvent (QEvent :: registerEventType()) {}, а затем предоставит метод, возвращающий этот тип или что-то в этом роде. – darkadept
Я считаю, что работает только в том случае, если MyEvent сам по себе является одноэлементным классом, что не очевидно из того, что вы уже сказали. Точкой хранения идентификатора события (int) отдельно является то, что вы можете надежно передавать одно и то же значение в QEvent ctor из вашего MyEvent ctor каждый раз. – 2010-02-26 04:47:41