Страницы

Поиск по вопросам

четверг, 5 декабря 2019 г.

Инициализация static в классе

#cpp #language_lawyer


Может кто-нибудь дать техническое объяснение, почему нельзя инициализировать статические
переменные внутри класса, а в функциях можно? 

Да, я знаю про const static и инициализацию static вне класса, но меня интересует
техническое объяснение этого процесса.

class A
{
public:
    static int a = 10; // нельзя
};




int main()
{
    static int b = 10; // можно
}

    


Ответы

Ответ 1



Это существенно разные вещи с точки зрения языка. В первом случае вы имеете просто объявление статического члена класса с внешним связыванием (external linkage), а во втором - определение статической переменной вообще без связывания (no linkage). Традиционно в С++ определение сущностей c (для которых требуются определения) - это задача пользователя. И инициализатор традиционно (за редкими исключениями) указывается именно в определении. Причина этого заключается в том, что выбор единицы трансляции, в которой будет располагаться определение c внешним связыванием в классическом С++ - это часть пользовательского замысла. Т.е. пользователь выбирает, в какой объектный файл попадет это определение. Также точное место расположения определения статического члена класса определяет его порядок инициализации (и деструкции) в рамках одной единицы трансляции. Это, с точки зрения компилятора, тоже часть пользовательского замысла. Поэтому компилятор ждет этого решения от вас, а не пытается принимать его сам. В С++17 появятся inline-переменные, т.е. фактически возможность при помощи ключевого слова inline сказать компилятору о том, что вас не интересует, где именно будет определен ваш статический член класса. Вот пользуясь эти синтаксисом вы и сможете наконец обойтись без явного указания места определения статического члена и, как следствие, также сможете указывать инициализатор прямо в определении класса class a { public: static inline int a = 10; };

Ответ 2



Внутри определения класса статические члены класса лишь объявляются, а не определяются. Поэтому внутри объявления класса статические члены класса могут иметь неполный тип. Например, #include struct A { static int a[]; }; int A::a[10]; int main() { return 0; } В этой демонстрационной программе в определении класса A объявляется статический член класса - массив a, который имеет неполный тип, то есть количество элементов массива не задано. Имейте в виду, что объявление класса может быть включено во множество единиц трансляции, в то время как определение объекта, включая статические члены класса, должно быть только в одной единице трансляции, если только объект не имеет внутреннее связывание. Кроме того инициализация статических объектов зависит от того, как он расположен относительно других статических объектов. Например, если инициализация некоторого статического объекта зависит от значения другого объекта, то этот статический объект должен быть расположен после того объекта, от которого его инициализация зависит. В функциях вы имеете дело с определениями объектов, если только они не объявлены со спецификатором extern. Но в последнем случае они не могут иметь инициализаторов. А в определениях классов вы имеете дело с объявлениями статических членов, а не с их определениями как объектов. С константными статическими членами классов проблем нет, так как они инициализируются констатными значениями, которые вычисляются на этапе компиляции.

Комментариев нет:

Отправить комментарий