3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
1

Создание объекта класса сразу после его описания (между "}" и ";")

11.07.2014, 13:00. Показов 1861. Ответов 8
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Пишу проект с дюжиной хедеров и десятком cpp-шников.
Мне нужны пара объектов класса А, которые должны существовать на протяжении всей программы.
Пытаюсь создать их в хедере сразу после описания класса (так):
C++
1
2
3
4
5
class A {
public:
   int a;
   A(int x=0) : a(x) {}
} objA;   // <-- создание объекта
Проблема - компилятор (MSVS 2013) бросает 2 ошибки:
error LNK2005: "class A objA" (?objA@@3VA@@A) уже определен в Connection.obj E:\_Мои_документы\_CPP Projects\HCS\main.obj HCS
тут main.obj и Connection.obj файлы, соответствующие одноимённым cpp-шникам, в которые включил include'ом хедер, в который вынесен указанный код класса А.
error LNK1169: обнаружен многократно определенный символ - один или более E:\_Мои_документы\_CPP Projects\HCS\Debug\HCS.exe 1 1 HCS
Хедер, само собой, с include-guard'ом.
Пробую экспериментировать: если вынести этот код в main.cpp (перед функцией main()) ошибок нет. Нет их и если вынести его в отдельный хедер, пока инклудю его только в одном месте (например в main.cpp). Но как только добавляю его инклудом в какой-то ещё файл проекта, ошибки появляются.
У меня ощущение, как будто не работает include-guard, но проверил - оформлен он корректно и переменная за #define'ом уникальна в проекте, и других ошибок не сыпется - только эти две.
Помогите пожалуйста разобраться.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.07.2014, 13:00
Ответы с готовыми решениями:

В зависимости от времени года "весна", "лето", "осень", "зима" определить погоду "тепло", "жарко", "холодно", "очень холодно"
В зависимости от времени года &quot;весна&quot;, &quot;лето&quot;, &quot;осень&quot;, &quot;зима&quot; определить погоду &quot;тепло&quot;,...

После каждого знака препинания (".", ",", ";") вставить в строку пробел, если там его нет
Выполните задания с использованием библиотечного класса string. Даны строка S. Необходимо после...

Для каждой строки найти слова, которые не имеют ни одного из букв: "l", "k", "r", "s" i "j"
Задано символьные строки. Строка состоит из нескольких слов (наборов символов), которые разделяются...

Вставить пробел после каждого символа "." "," "!" или "?", если за этими символами не следует пробел
Вставить пробел после каждого символа &quot;.&quot; &quot;,&quot; &quot;!&quot; или &quot;?&quot;, если за этими символами не следует...

8
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
11.07.2014, 13:08 2
Цитата Сообщение от SaShka K Посмотреть сообщение
objA
Это имя объекта. Который находится внутри вашего
Цитата Сообщение от SaShka K Посмотреть сообщение
include-guard
Следовательно сколько раз у вас вставится ваш хедер, столько одинаковых объектов у вас создастся. О чем вам и говорит ошибка.

Уберите из описательной части вообще любые объявления.
1
1130 / 789 / 232
Регистрация: 12.04.2010
Сообщений: 2,012
11.07.2014, 13:17 3
Лучший ответ Сообщение было отмечено SaShka K как решение

Решение

Цитата Сообщение от SaShka K Посмотреть сообщение
cpp-шникам, в которые включил include'ом хедер
Включение заголовочного файла в cpp-файл ( #include "a.h" ) эквивалентно копированию его содержимого в cpp-файл.
Цитата Сообщение от SaShka K Посмотреть сообщение
добавляю его инклудом в какой-то ещё файл проекта
Это то же самое, что в двух cpp-файлах определить объект с одним именем (A objA; ).
1
3 / 3 / 0
Регистрация: 16.01.2014
Сообщений: 55
11.07.2014, 13:52  [ТС] 4
Спасибо за ответы. Я, кажется, это даже знал, но как-то вылетело. Позвольте, проговорю для уверенности, что понимаю верно:

Т.е. Include-guard НЕ гарантирует, что хедер будет вставлен единственный раз в рамках проекта, а гарантирует то, что он не будет вставлен повторно в рамках единицы компиляции. (т.е. одного cpp-шника со всеми, подтягиваемыми им прямо, или опосредованно хедерами).

Итого - склеиваются все файлы проекта именно в такие единицы компиляции. А точки взаимодействия между этими единицами появляются при вызове из одной из них метода, определённого в другой.
Насколько я далёк от истины?
Спасибо!
0
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
11.07.2014, 14:40 5
SaShka K, если в трех словах, то непосредственно перед компиляцией препроцессор проходит весь текст программы (как именно происходит разбиение на единицы компиляции я не знаю; Evg, может наверное рассказать), раскрывает все инклуды и тупо запихивает весь встречающийся код в один большой длинный текст. Если инклуд защищен, как вы выражаетесь, Include-guard-ом, то он попросту не вставляется в этот текст, если уже одна копия его там имеется. И вот этот уже длинный текст передается компилятору.

Вот здесь можно почитать подробнее: Препроцессорные директивы в C/C++ (#include, #define и прочее)
Очень абстрактное представление о препроцессировании: https://www.cyberforum.ru/atta... 1360839465

Добавлено через 17 минут
А, ну собственно.
1
17410 / 9246 / 2260
Регистрация: 30.01.2014
Сообщений: 16,178
11.07.2014, 14:42 6
Цитата Сообщение от SaShka K Посмотреть сообщение
Т.е. Include-guard НЕ гарантирует, что хедер будет вставлен единственный раз в рамках проекта, а гарантирует то, что он не будет вставлен повторно в рамках единицы компиляции. (т.е. одного cpp-шника со всеми, подтягиваемыми им прямо, или опосредованно хедерами).
Абсолютно верно.

Цитата Сообщение от SaShka K Посмотреть сообщение
А точки взаимодействия между этими единицами появляются при вызове из одной из них метода, определённого в другой.
Точки взаимодействия разруливает линкер. Именно он и выдал тебе ошибку про повторное определение.

Почитай еще что-нибудь по теме ODR. Это очень важно и напрямую касается твоей темы.

Цитата Сообщение от SatanaXIII Посмотреть сообщение
как именно происходит разбиение на единицы компиляции я не знаю;
Что непосредственно отдано компилятору, то и есть единица трансляции. Компилятор вызывается столько раз, сколько, грубо говоря, задал программист. Если взять, например, проект студии, с 10 cpp файлами в нем, то компилятор будет вызван 10 раз для каждого из этих файлов. Все, что было включено в такой файл и непосредственное содержимое этого файла будет составлять единицу трансляции (итого 10 единиц). Если же мы пишем, например, makefile, то там можно более наглядно посмотреть этот процесс. Можно, скажем, взять за исходный txt-файл. Тогда этот txt и все, что он включает, тоже будет единицей трансляции. Это я к тому, что единица трансляции - это не всегда c или cpp файлы.
1
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
11.07.2014, 14:49 7
DrOffset, все так. Но единица трансляции и единица компиляции - разные понятия. Это меня смущает. ..А хотя да, всякими штуками типа extern это ж все как раз и обходится.
0
17410 / 9246 / 2260
Регистрация: 30.01.2014
Сообщений: 16,178
11.07.2014, 14:56 8
Цитата Сообщение от SatanaXIII Посмотреть сообщение
Но единица трансляции и единица компиляции - разные понятия.
Это одно и то же. К тому же, термин "единица компиляции" (compilation unit) используется только в паре мест стандарта, в разделе о различиях между С и С++. И там смысл эквивалентен смыслу термина "единица трансляции" (translation unit).
2
27 / 26 / 16
Регистрация: 02.12.2013
Сообщений: 79
11.07.2014, 15:02 9
Цитата Сообщение от SaShka K Посмотреть сообщение
Т.е. Include-guard НЕ гарантирует, что хедер будет вставлен единственный раз в рамках проекта
Это гарантировано для единицы трансляции. Количество единиц трансляции в проекте - количество *.cpp.
Include-guard может гарантировать что-то на уровне препроцессора. "рамки проекта" ему не ведомы.

Ошибки тебе линковщик сыпет. У него никаких guard-ов нет, есть имена и их надо резольвить. А когда в разных объектниках имена одинаковые как их в кучу собирать?.

"Определение" переменной в программе должно быть только одно. А вот объявлений сколько угодно.
Это добиваются обычно следующим способом
C++
1
2
3
extern int a; // объявление  - можно писать где угодно и сколько угодно раз
int a; // объявление и определение - можно написать только один раз,
        // и надо хорошо подумать на тему того что до первого использования переменную надо "создать".
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
11.07.2014, 15:02
Помогаю со студенческими работами здесь

Создать классы "Computer", "Software", "User" и реализовать взаимодействие объектов этих типов между собой
Помогите решить задачку,нужна в инст на экзамен. Составить программу реализующую: ...

Реализовать классы "Воин", "Пехотинец", "Винтовка", "Матрос", "Кортик" (наследование)
Разработать программу с использованием наследования классов, реализующую классы: − воин;...

Необходимо между каждой парой цифр поставить знак "<", ">" или "="
Дана строка, состоящая из цифр. Необходимо между каждой парой цифр поставить знак &quot;&lt;&quot;, &quot;&gt;&quot; или &quot;=&quot;....

С++ консольное приложение win32, матерится на первое "pow" после "if", а на "system" говорит что неопределён.
#define _CRT_SECURE_NO_WARNINGS #include &quot;stdafx.h&quot; #include &lt;math.h&gt; #include &lt;iostream&gt;...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru