Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.83
Chelioss
180 / 180 / 4
Регистрация: 08.01.2011
Сообщений: 1,133
#1

Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. - C++

08.01.2012, 18:50. Просмотров 1489. Ответов 8
Метки нет (Все метки)

Есть файл Point.h:
Point.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef POINT_GUARD
#define POINT_GUARD
 
//--------------------------------------------------------------------------------------------
 
class Point
{
public:
    unsigned int x,y;
    Point( const int m_x, const int m_y ): x( m_x ), y( m_y ) {}
    Point(): x(0), y(0) {}
};
 
bool operator == ( const Point &left, const Point &right )
{
    return ( left.x == right.x ) && ( left.y == right.y );
}
bool operator != ( const Point &left, const Point &right )
{
    return !( left == right );
}
 
//--------------------------------------------------------------------------------------------
 
#endif // POINT_GUARD

Напишу куда подключается файл Point.h.
Point.h подключается в Graph.h и MyWindow.h. В GUI.h подключаются файлы Graph.h и MyWindow.h.
В Main.cpp подключаются GUI.h и Graph.h
В MyWindow.cpp подключаются MyWindow.h и Graph.h и GUI.h.
При компоновке появляется такая ошибка:
Ошибки
1>MyWindow.obj : error LNK2005: "bool __cdecl operator==(class Point const &,class Point const &)" (??8@YA_NABVPoint@@0@Z) уже определен в Main.obj
1>MyWindow.obj : error LNK2005: "bool __cdecl operator!=(class Point const &,class Point const &)" (??9@YA_NABVPoint@@0@Z) уже определен в Main.obj

Причем на Main.obj компоновщик не ругается, хотя там тоже подключается косвенно Point.h.
Почему обертка(защита) не срабатывает я не понимаю.

Если добавить в файл Point.h перед двумя перегрузками операторов == и != спецификатор inline, то ошибка пропадает. Почему?
inline это инструкция для препроцессора как #define #endif и т.д.?

Point.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef POINT_GUARD
#define POINT_GUARD
 
//--------------------------------------------------------------------------------------------
 
class Point
{
public:
    unsigned int x,y;
    Point( const int m_x, const int m_y ): x( m_x ), y( m_y ) {}
    Point(): x(0), y(0) {}
};
 
inline bool operator == ( const Point &left, const Point &right )
{
    return ( left.x == right.x ) && ( left.y == right.y );
}
inline bool operator != ( const Point &left, const Point &right )
{
    return !( left == right );
}
 
//--------------------------------------------------------------------------------------------
 
#endif // POINT_GUARD
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.01.2012, 18:50
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. (C++):

Назначение директив препроцессора: #ifndef, #define, #endif - C++
Объясните, что обозначают эти директивы? Заем это использовать в классах? #ifndef myclass #define myclass class someclass { ...

Объясните, в чем суть директив #ifndef/#define/#endif - C++
Не понял в чем суть директив: #ifndef .. #define.. #endifОбъясните пожалуйста..это как - то связано с хедерами, но вот как ??

Нюансы синтаксиса: #pragma once и ifndef define endif это одно и тоже? - C++
Я недопонял #pragma once и ifndef define endif это одной и тоже?

Команды #ifndef #ifdef и #endif - C++
Помогите разобраться с командами #ifndef #endif и #ifndef в книге все как то не понятно объяснено или же лучше если у кого то есть видео на...

#define VS inline - C++
Что работает быстрее: #define SQR(x) x*x void Func() { for(int i = 0; i < 10; ++i) { cout << SQR(i) << endl; ...

inline и define - C++
Почему использовать inline-функции лучше, чем использовать команду препроцессора #define? Смысл в том, что лучше лишний раз не трогать...

8
NoMasters
Псевдослучайный
1762 / 1105 / 73
Регистрация: 13.09.2011
Сообщений: 3,141
08.01.2012, 18:59 #2
Принципиального отличия между .h и .cpp файлами нет, компилируется в итоге один файл, содержащий текст всех включений. Поэтому у вас во всех объектных файлах действительно присутствует по реализации этих функций. А инлайн функции как таковые отсутствуют в итоговых файлах, их тело просто замещает вызовы.
А макрообертки используются для избежания повторных включений внутри одного компилируемого файла.
1
Chelioss
180 / 180 / 4
Регистрация: 08.01.2011
Сообщений: 1,133
08.01.2012, 19:11  [ТС] #3
NoMasters
Из вашего сообщения не понятно почему обертка(защита) не помогла.
Вот эксперимент, в котором обертка(защита) помогла:
код
Файл Point.h:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef POINT_GUARD
#define POINT_GUARD
 
struct Point
{
    unsigned int x, y;
    Point() : x(0), y(0) {}
};
 
bool operator == ( const Point &left, const Point &right )
{
    return ( left.x == right.x ) && ( left.y == right.y );
}
 
bool operator != ( const Point &left, const Point &right )
{
    return !( left == right );
}
 
#endif
Файл main.cpp:
C++
1
2
3
4
5
#include "Point.h"
#include "Point.h"
int main()
{
}


Добавлено через 5 минут
Я думаю тут надо понять как работает обертка(защита) и тогда появится ответ на мой вопрос.
0
NoMasters
Псевдослучайный
1762 / 1105 / 73
Регистрация: 13.09.2011
Сообщений: 3,141
08.01.2012, 19:18 #4
Не помогла потому, что собиралось несколько отдельных объектных файлов. В каждом действительно могло оказаться не более одной реализации, но от этого при линковке лучше не станет.
Обертка работает очень просто: если макрос уже определён, код повторно не включается.
1
Chelioss
180 / 180 / 4
Регистрация: 08.01.2011
Сообщений: 1,133
08.01.2012, 19:41  [ТС] #5
Цитата Сообщение от NoMasters Посмотреть сообщение
макрос уже определён
Определение макроса действует на весь проект или только на один файл?
0
NoMasters
Псевдослучайный
1762 / 1105 / 73
Регистрация: 13.09.2011
Сообщений: 3,141
08.01.2012, 19:44 #6
Отдельно на каждый файл, скармливаемый компилятору.
1
Chelioss
180 / 180 / 4
Регистрация: 08.01.2011
Сообщений: 1,133
08.01.2012, 20:26  [ТС] #7
В общем, непонято откуда ошибка взялась.
0
NoMasters
Псевдослучайный
1762 / 1105 / 73
Регистрация: 13.09.2011
Сообщений: 3,141
08.01.2012, 20:36 #8
Оттуда, что компилируемых файлов в проекте было больше одного.
1
Evg
Эксперт CАвтор FAQ
18036 / 6268 / 428
Регистрация: 30.03.2009
Сообщений: 17,244
Записей в блоге: 28
09.01.2012, 12:36 #9
Цитата Сообщение от Chelioss Посмотреть сообщение
В общем, непонято откуда ошибка взялась
Всё понятно. В заголовочные файлы можно складывать только то, что разрешено включать сразу в несколько файлов: описания типов, описания макросов, описание функций и методов, для которых допустимы множественные определения (в случае Си++ это функции и методы с модификатором inline).

Ты же в своём коде впендюрил туда оператор (функцию). Если бы оператор был описан внутри класса, то он бы имел неявный модификатор inline и всё было бы хорошо. Но он описан вне класса, а потому в каждом файле, в котором делается подключение твоего Point.h, образуется одна копия оператора, что и влечёт за собой множественное определение на линковке.

В проекте, состоящем из нескольких файлов *.cpp, каждый файл *.cpp компилируется отдельным запуском компилятора независимо от остальных файлов *.cpp. А guard, кстати, используется не для этих целей

Добавлено через 1 минуту
Цитата Сообщение от Evg Посмотреть сообщение
Если бы оператор был описан внутри класса, то он бы имел неявный модификатор inline и всё было бы хорошо
Оператор не является членом класса, это я проглядел. Поэтому правильным было бы сказать, что "если бы оператор был описан с модификатором inline"
1
09.01.2012, 12:36
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.01.2012, 12:36
Привет! Вот еще темы с ответами:

Ifndef-define-endif - C++ Qt
Qt Creator по умолчанию создаёт хэдер любого класса с подобной шапкой: #ifndef MYCLASS_H // ЭТО #define MYCLASS_H // И ЭТО ...

#ifndef #endif и extern - Visual C++
#ifndef #endif и extern Как применять эти директивы и зачем они? без них обходился и раньше, но в чужом коде их увидел. ...

Странное предупреждение при использовании #ifndef-#endif - Visual C++
Создаю заголовочный файл: #ifndef EXAMPLE_H #define EXAMPLE_H bool Abrakadabra(int a); #endif Фрагмент кода "bool"...

Как реализовать директиву #define для создания шаблона отпределения #define ? - C (СИ)
Здравствуйте уважаемые. При написании программы появилась необходимость задать шаблон создания #define через #define (извините за...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru