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

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

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.83
Chelioss
179 / 179 / 4
Регистрация: 08.01.2011
Сообщений: 1,131
08.01.2012, 18:50     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. #1
Есть файл 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
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.01.2012, 18:50     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик.
Посмотрите здесь:

Объясните, в чем суть директив #ifndef/#define/#endif C++
C++ inline функции vs инструкции inline функций
#define VS inline C++
inline и define C++
Почему отказались от #ifndef? C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
NoMasters
Псевдослучайный
1737 / 1080 / 69
Регистрация: 13.09.2011
Сообщений: 3,093
08.01.2012, 18:59     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. #2
Принципиального отличия между .h и .cpp файлами нет, компилируется в итоге один файл, содержащий текст всех включений. Поэтому у вас во всех объектных файлах действительно присутствует по реализации этих функций. А инлайн функции как таковые отсутствуют в итоговых файлах, их тело просто замещает вызовы.
А макрообертки используются для избежания повторных включений внутри одного компилируемого файла.
Chelioss
179 / 179 / 4
Регистрация: 08.01.2011
Сообщений: 1,131
08.01.2012, 19:11  [ТС]     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. #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 минут
Я думаю тут надо понять как работает обертка(защита) и тогда появится ответ на мой вопрос.
NoMasters
Псевдослучайный
1737 / 1080 / 69
Регистрация: 13.09.2011
Сообщений: 3,093
08.01.2012, 19:18     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. #4
Не помогла потому, что собиралось несколько отдельных объектных файлов. В каждом действительно могло оказаться не более одной реализации, но от этого при линковке лучше не станет.
Обертка работает очень просто: если макрос уже определён, код повторно не включается.
Chelioss
179 / 179 / 4
Регистрация: 08.01.2011
Сообщений: 1,131
08.01.2012, 19:41  [ТС]     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. #5
Цитата Сообщение от NoMasters Посмотреть сообщение
макрос уже определён
Определение макроса действует на весь проект или только на один файл?
NoMasters
Псевдослучайный
1737 / 1080 / 69
Регистрация: 13.09.2011
Сообщений: 3,093
08.01.2012, 19:44     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. #6
Отдельно на каждый файл, скармливаемый компилятору.
Chelioss
179 / 179 / 4
Регистрация: 08.01.2011
Сообщений: 1,131
08.01.2012, 20:26  [ТС]     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. #7
В общем, непонято откуда ошибка взялась.
NoMasters
Псевдослучайный
1737 / 1080 / 69
Регистрация: 13.09.2011
Сообщений: 3,093
08.01.2012, 20:36     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. #8
Оттуда, что компилируемых файлов в проекте было больше одного.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.01.2012, 12:36     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик.
Еще ссылки по теме:

C++ Inline функции - на сколько должна быть маленькая функция, чтоб она подошла под inline?
C++ #ifndef и #include
Как на физическом уровне работает компоновщик в приведенном случае C++

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

Или воспользуйтесь поиском по форуму:
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16824 / 5245 / 320
Регистрация: 30.03.2009
Сообщений: 14,125
Записей в блоге: 26
09.01.2012, 12:36     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик. #9
Цитата Сообщение от Chelioss Посмотреть сообщение
В общем, непонято откуда ошибка взялась
Всё понятно. В заголовочные файлы можно складывать только то, что разрешено включать сразу в несколько файлов: описания типов, описания макросов, описание функций и методов, для которых допустимы множественные определения (в случае Си++ это функции и методы с модификатором inline).

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

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

Добавлено через 1 минуту
Цитата Сообщение от Evg Посмотреть сообщение
Если бы оператор был описан внутри класса, то он бы имел неявный модификатор inline и всё было бы хорошо
Оператор не является членом класса, это я проглядел. Поэтому правильным было бы сказать, что "если бы оператор был описан с модификатором inline"
Yandex
Объявления
09.01.2012, 12:36     Как влияет inline и обертка(#ifndef #define #endif) .h файла на компоновщик.
Ответ Создать тему
Опции темы

Текущее время: 04:08. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru