В чем причина отсутствия статического конструктора в С++?
В чем причина отсутствия статического конструктора в С++?
Если бы это было разрешено, мы бы инициализировали все статические члены в нем в одном месте очень организованным образом, так как:
//illegal C++
class sample
{
public:
static int some_integer;
static std::vector<std::string> strings;
//illegal constructor!
static sample()
{
some_integer = 100;
strings.push_back("stack");
strings.push_back("overflow");
}
};
В отсутствии статического конструктора очень сложно иметь статический вектор и заполнять его значениями, как показано выше. статический конструктор элегантно решает эту проблему. Мы могли бы инициализировать статические элементы очень организованным способом.
Итак, почему С++ не имеет статического конструктора? В конце концов, другие языки (например, С#) имеют статический конструктор!
Ответы
Ответ 1
Использование задачи статического инициализации в качестве предлога для того, чтобы не вводить эту особенность в язык, является и всегда было вопросом статус-кво - оно не было введено, потому что оно не было введено, и люди продолжают думать, что порядок инициализации был причина не вводить его, даже если проблема порядка имеет простое и очень простое решение.
Порядок инициализации, если бы люди действительно хотели решить проблему, у них было бы очень простое и понятное решение:
//called before main()
int static_main() {
ClassFoo();
ClassBar();
}
с соответствующими объявлениями:
class ClassFoo {
static int y;
ClassFoo() {
y = 1;
}
}
class ClassBar {
static int x;
ClassBar() {
x = ClassFoo::y+1;
}
}
Итак, ответ: нет причин, чтобы его там не было, по крайней мере, не было технического.
Ответ 2
Это не имеет смысла для С++ - классы не являются объектами первого класса (например, java).
Конструктор A (static | anything) предполагает, что что-то построено - и классы С++ не построены, они просто есть.
Вы можете легко добиться такого же эффекта:
//.h
struct Foo {
static std::vector<std::string> strings;
};
//.cpp
std::vector<std::string> Foo::strings(createStrings());
IMO просто не нужно использовать еще один синтаксический способ сделать это.
Ответ 3
В каком блоке трансляции будут размещены статические объекты?
Как только вы учтете тот факт, что статика должна быть помещена в один (и только один) TU, тогда не "очень сложно" пройти весь путь и назначить значения для них в функции:
// .h
class sample
{
public:
static int some_integer;
static std::vector<std::string> strings;
};
//.cpp
// we'd need this anyway
int sample::some_integer;
std::vector<std::string> sample::strings;
// add this for complex setup
struct sample_init {
sample_init() {
sample::some_integer = 100;
sample::strings.push_back("stack");
sample::strings.push_back("overflow");
}
} x;
Если вы действительно хотите, чтобы код sample_init
отображался в определении класса sample
, вы могли бы даже поместить его туда как вложенный класс. Вам просто нужно определить экземпляр этого объекта в том же месте, где вы определяете статику (и после того, как они были инициализированы через их конструкторы по умолчанию, иначе, конечно, вы не можете push_back
что-либо).
С# был изобретен через 15-20 лет после С++ и имеет совершенно другую модель сборки. Это не все, что удивительно, что он предлагает разные функции, и что некоторые вещи менее просты в С++, чем в С#.
С++ 0x добавляет функции, облегчающие инициализацию векторов некоторыми данными, называемыми "списками инициализаторов"
Ответ 4
Вы можете обойтись, поставив свои "статические" члены в своем классе со своим собственным конструктором, который выполняет свою инициализацию:
class StaticData
{
int some_integer;
std::vector<std::string> strings;
public:
StaticData()
{
some_integer = 100;
strings.push_back("stack");
strings.push_back("overflow");
}
}
class sample
{
static StaticData data;
public:
sample()
{
}
};
Ваш статический член data
должен быть инициализирован, прежде чем вы сначала попытаетесь получить к нему доступ. (Вероятно, до основного, но не обязательно)
Ответ 5
Static подразумевает функцию, которая диссоциируется с объектом. Поскольку построены только объекты, неясно, почему статический конструктор имел бы какую-либо пользу.
Вы всегда можете держать объект в статической области, который был создан в статическом блоке, но используемый вами конструктор все равно будет объявлен как нестатический. Нет правила, указывающего на то, что вы не можете вызывать нестатический метод из статической области.
Наконец, С++/C определяет начало программы, когда будет введена функция main
. Статические блоки вызываются до ввода функции main
как часть настройки "среды" оцениваемого кода. Если ваша среда диктует полный контроль над настройкой и срывом, то легко утверждать, что на самом деле это не какое-то экологическое приспособление, а не наследование процедурного компонента программы. Я знаю, что последний бит - это своего рода философия кода (и что его обоснование можно интерпретировать по-разному), но не следует ставить критический код "до" официального запуска исполняемого файла, передающего "полный контроль" на написанный код программистом.