Некоторые вопросы об ODR, декларации и определениях

Извините, если вопросы старые или немного глупые.

Я знаю основы объявления и определения, но, похоже, в C ++ есть много несоответствий или «исключений», которые делают его не гармоничным, по крайней мере, для меня. Или я что-то неправильно понял.

Итак, в файлах заголовков мы объявляем некоторые переменные и определяем типы классов (также слышали о «объявлении класса», не знаю, какой из них более точный); внутри каждого класса мы объявляем переменные-члены и функции. Затем в каком-нибудь файле .cc / .cpp мы определяем только функции-члены для реализации класса. Если «к сожалению» существует статическая переменная / функция-член, которая будет считаться особой и в значительной степени независимой от связанного класса, ее необходимо определить вне класса, поскольку это единственный вид «уродов». "среди переменных-членов.

Когда файл .cpp #include содержит файл заголовка, который определяет тип класса (обратите внимание, что определение типа класса в этом файле заголовка кажется «неполным», поскольку его функции определены где-то еще.), Файл .cpp помещает определение типа класса в начало вместе с другими возможными объявлениями.

В файле .cpp статические переменные-члены класса #included уже определены в реализации .cpp вместе с функциями-членами, тогда как насчет нестатических «нормальных» переменных-членов, если экземпляр класса создается? Предположим, это Class A;, тогда будут ли определены нестатические переменные-члены, если A a;? Конечно, объект a типа A определен, но его нестатические переменные-члены также определены (определены в том смысле, что выделено памятью)? Если это так, то два объекта, скажем a1 и a2, одного типа A были бы полностью совместимы, чтобы быть вместе, потому что a1.mem_var_1 и a2.mem_var_1 имеют разные определения по отношению к разным именам экземпляров класса? Или у них одно и то же определение, но с разными значениями и копиями?

А как насчет функций-членов? Они были определены в файле .cpp для типа класса, но когда мы создаем несколько экземпляров, разве они не будут иметь одно и то же определение в .cpp, но будут иметь разные копии в памяти (я предполагаю, что несколько копий одной и той же функции-члена необходимы, по крайней мере, для разных значений локальных переменных внутри)? А как насчет статических функций?

ИЛИ, я что-то неправильно понимаю, потому что мы, программисты "определяем" что-то в файле НЕ РАВНО компилятору и компоновщику " определить "что-нибудь в файле? Что на самом деле означает и означает определение? Мы записываем в файл что-то, чтобы «определить» что-то, но система может «определить» по-другому, по крайней мере, в смысле тайного создания нескольких копий и прочего?

Мои головные боли...


person vincentvangaogh    schedule 07.07.2015    source источник
comment
возможный дубликат В чем разница между определением и декларация?   -  person NathanOliver    schedule 07.07.2015
comment
@ShafikYaghmour Я бы сказал, что он отвечает по крайней мере на половину вопроса, но я бы сказал, что он слишком общий, поскольку это несколько вопросов в одном. Я просто хотел указать OP на хорошую информацию. возможно, мне следовало сказать, что это связано.   -  person NathanOliver    schedule 07.07.2015
comment
Да, отчасти помогает, но не всем.   -  person vincentvangaogh    schedule 07.07.2015
comment
@NathanOliver предоставляет полезную ссылку, которая отвечает примерно на половину вашего вопроса, но поскольку этот вопрос написан, он слишком широк, в нем слишком много вопросов и нет конкретных примеров. Вам необходимо указать конкретную проблему вместе с минимальным, полным и поддающимся проверке примером, который иллюстрирует проблему, если это возможно.   -  person Shafik Yaghmour    schedule 08.07.2015


Ответы (1)


Причина этого - историческая. Когда был изобретен C, память и процессор были маленькими и дорогими. Если в вашем проекте было 20 файлов, компилятор просто не смог бы загрузить всю память и разрешить символы. Resolve означает выделение достаточного и правильного места для каждой функции, структуры и переменной.

Теперь представьте, что у нас есть 2 файла cpp, один определяет структуру String, а другой определяет структуру Rectangle. Чтобы функции работали со String и Rectangle в обоих файлах, компилятор должен загрузить оба файла и проанализировать их. В те времена это была бы очень интенсивная операция по памяти.

Поэтому некоторые дополнительные файлы, заголовки были приняты. Эти заголовки просто сообщают памяти компилятора информацию о каждом типе, используемом cpp. Затем компилятор может компилировать только на основе файла cpp и всех зависимых заголовков в файлы obj.

После того, как все cpp были скомпилированы, происходит компоновка, в которой собираются все файлы obj. Теперь критически важно, чтобы переменные были определены одинаково для всех cpp, иначе некоторые cpp будут работать с прямоугольником размером 8 байт, а другой cpp будет работать с прямоугольником размером 12 байтов, а когда их объединить -> бац!

person AndreiM    schedule 07.07.2015