Russian Qt Forum
Ноябрь 24, 2024, 00:30 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Multiple definition of function  (Прочитано 8743 раз)
serg_hd
Хакер
*****
Offline Offline

Сообщений: 668



Просмотр профиля
« : Февраль 24, 2011, 20:17 »

Здравствуйте, вопрос, возможно, покажется нубским, но всё же рискну. Есть у меня в проекте один файлик, defines.h, в котором я декларирую и тут же инициализирую различные нужности, например енумы, структуры, классы, typedef'ы, define'ы, etc. И подключаю этот хидер для нужного мне класса когда надо (т.е. подключается он во всём проекте не единожды). Но решил в defines.h также добавить:
Код
C++ (Qt)
namespace MySpace
{
QString getStr()
{
 QString str;
 //...  
 return str;
}
}
 

Препроцессинг нормально, компиляция нормально, но линковщик стал неравнодушен:

.../defines.h:188: multiple definition of `MySpace::getStr()'

Так вот, собственно, и вопрос: почему? Ведь выше от неё описаны классы со своими методами (именно инициализированы, как и эта функция) и куча других данных, а не нравится именно эта функция. Хорошо, разделил на .h и .cpp. Теперь в defines.h только декларация этой функции (а всё что выше не трогал, то есть там присутствуют и инициализации в отличие от этой функции):

Код
C++ (Qt)
namespace MySpace
{
QString getStr();
}
 

Ну а в defines.cpp инициализировал функцию как обычно. Всё заработало. Так вот, нельзя ли обойтись только .h-файлом? И вообще, может быть есть какие-то негласные стандарты для осуществления подобного подхода? Просто мне показался вариант использования функции MySpace::getStr() как наиболее удобным, а использовать её как статическую - банально.

« Последнее редактирование: Март 18, 2011, 15:30 от serg_hd » Записан

kubuntu/Win7/x64/NetBeans
Blackwanderer
Гость
« Ответ #1 : Февраль 24, 2011, 20:21 »

А защита от множественного включения в вашем *.h файле есть?
Записан
serg_hd
Хакер
*****
Offline Offline

Сообщений: 668



Просмотр профиля
« Ответ #2 : Февраль 24, 2011, 20:21 »

А защита от множественного включения в вашем *.h файле есть?
Конечно, стражи на месте. Т.е. в одном классе (у меня для каждого класса свои, отдельные пары .h/.cpp) 2х и более подключений defines.h быть не может.
« Последнее редактирование: Февраль 24, 2011, 20:37 от serg_hd » Записан

kubuntu/Win7/x64/NetBeans
serg_hd
Хакер
*****
Offline Offline

Сообщений: 668



Просмотр профиля
« Ответ #3 : Февраль 24, 2011, 20:23 »

Я так понимаю, что если проинициализирован не тип (класс, структура и т.п.), а функция, как в моём случае, то линковщик её воспринимает глобально. Т.е. каждый раз, когда есть инклуд defines.h в какой-либо файл выдаёт что функция уже существует.
Записан

kubuntu/Win7/x64/NetBeans
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Февраль 24, 2011, 20:43 »

Ну а в defines.cpp инициализировал функцию как обычно. Всё заработало. Так вот, нельзя ли обойтись только .h-файлом?
Если хотите тело ф-ции в h файле - объявляйте ее как inline. Если связались с template - все тела должны быть в h файлах

Я так понимаю, что если проинициализирован не тип (класс, структура и т.п.), а функция, как в моём случае, то линковщик её воспринимает глобально. Т.е. каждый раз, когда есть инклуд defines.h в какой-либо файл выдаёт что функция уже существует.
Да, т.к. эта ф-ция будет в каждом cpp который включает этот h
« Последнее редактирование: Февраль 24, 2011, 20:45 от Igors » Записан
serg_hd
Хакер
*****
Offline Offline

Сообщений: 668



Просмотр профиля
« Ответ #5 : Февраль 24, 2011, 20:52 »

Если хотите тело ф-ции в h файле - объявляйте ее как inline. Если связались с template - все тела должны быть в h файлах
Совет с inline помог, спасибо (не знал, что он влияет также на "глобальность" функции). Но с шаблонами позволю себе не согласиться, их можно резделить, специально пробовал. Только при разделении в .cpp нужно описывать каждый тип с которым будет работать шаблон, а это дополнительно столько строк, сколько будет типов, принимаемых шаблоном, что не есть хорошо. Просто хотел сказать, что на самом деле не "должны", а "настоятельно рекомендуется" Улыбающийся
« Последнее редактирование: Февраль 24, 2011, 22:13 от serg_hd » Записан

kubuntu/Win7/x64/NetBeans
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #6 : Февраль 24, 2011, 21:24 »

>>Я так понимаю, что если проинициализирован не тип (класс, структура и т.п.), а функция,
что понимается под инициализацией функции?
Записан

Юра.
serg_hd
Хакер
*****
Offline Offline

Сообщений: 668



Просмотр профиля
« Ответ #7 : Февраль 24, 2011, 21:27 »

>>Я так понимаю, что если проинициализирован не тип (класс, структура и т.п.), а функция,
что понимается под инициализацией функции?
описание её тела
Записан

kubuntu/Win7/x64/NetBeans
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Февраль 24, 2011, 21:47 »

Но с шаблонами позволю себе не согласиться, их можно резделить, специально пробовал. Только при разделении в декларации нужно описывать каждый тип с которым будет работать шаблон, а это дополнительно столько строк, сколько будет типов, принимаемых шаблоном, что не есть хорошо. Просто хотел сказать, что на самом деле не "должны", а "настоятельно рекомендуется" Улыбающийся
"Должны" - иначе Вы сможете вызывать template ф-ции только из того cpp файла где их тела (но не из другого). Если template класс имеет static члены, они также должны быть в h файле (и их сынтаксыс с непривычки бьет по ушам  Улыбающийся)
Записан
serg_hd
Хакер
*****
Offline Offline

Сообщений: 668



Просмотр профиля
« Ответ #9 : Февраль 24, 2011, 21:51 »

Но с шаблонами позволю себе не согласиться, их можно резделить, специально пробовал. Только при разделении в декларации нужно описывать каждый тип с которым будет работать шаблон, а это дополнительно столько строк, сколько будет типов, принимаемых шаблоном, что не есть хорошо. Просто хотел сказать, что на самом деле не "должны", а "настоятельно рекомендуется" Улыбающийся
"Должны" - иначе Вы сможете вызывать template ф-ции только из того cpp файла где их тела (но не из другого). Если template класс имеет static члены, они также должны быть в h файле (и их сынтаксыс с непривычки бьет по ушам  Улыбающийся)
а, речь идёт о шаблонных функциях. Я думал о классах, содержащих шаблонные методы.
Записан

kubuntu/Win7/x64/NetBeans
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Февраль 24, 2011, 21:55 »

а, речь идёт о шаблонных функциях. Я думал о классах, содержащих шаблонные методы.
Без разницы, template ф-ция - член или просто ф-ция. Должны быть "в одной единице компиляции"
Записан
serg_hd
Хакер
*****
Offline Offline

Сообщений: 668



Просмотр профиля
« Ответ #11 : Февраль 24, 2011, 22:04 »

а, речь идёт о шаблонных функциях. Я думал о классах, содержащих шаблонные методы.
Без разницы, template ф-ция - член или просто ф-ция. Должны быть "в одной единице компиляции"

Класс разделяется без проблем:
SomeClass.h
Код
C++ (Qt)
class SomeClass
{
 public:
 template<class T> void Fun(T* pT);
};
 

SomeClass.cpp
Код
C++ (Qt)
template void SomeClass::Fun<int>(int*); //тип 1
template void SomeClass::Fun<double>(double*);//тип 2
template<class T> void SomeClass::Fun(T* pT)
{
 //...
}
 
« Последнее редактирование: Февраль 25, 2011, 00:59 от serg_hd » Записан

kubuntu/Win7/x64/NetBeans
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Февраль 24, 2011, 23:00 »

Класс разделяется без проблем:
Попробуйте вызвать Fun() из др. cpp (а не из SomeClass.cpp). Линкеру это не понравится..
Записан
serg_hd
Хакер
*****
Offline Offline

Сообщений: 668



Просмотр профиля
« Ответ #13 : Февраль 25, 2011, 00:26 »

Попробуйте вызвать Fun() из др. cpp (а не из SomeClass.cpp). Линкеру это не понравится..
Так ведь в SomeClass.cpp я его и не вызываю. Я его там инициализирую (описываю) и декларирую другие типы, которые будет использовать шаблон, как я уже выше упоминал.

По сабжу:
SomeClass.h
Код
C++ (Qt)
#ifndef SOMECLASS_H
#define SOMECLASS_H
 
class SomeClass
{
public:
 template<class T> void Fun(T pT);
};
 
#endif
 

SomeClass.cpp
Код
C++ (Qt)
#include <iostream>
#include "SomeClass.h"
 
template void SomeClass::Fun<int>(int); //тип 1
template void SomeClass::Fun<double>(double);//тип 2
template<class T> void SomeClass::Fun(T pT)
{
std::cout << pT << std::flush;
}
 

MyClass1.h
Код
C++ (Qt)
#ifndef MYCLASS1_H
#define MYCLASS1_H
 
class SomeClass;
 
class MyClass1
{
public:
MyClass1();
SomeClass* t_member;
};
 
#endif
 

MyClass1.cpp
Код
C++ (Qt)
#include "MyClass1.h"
#include "SomeClass.h"
 
MyClass1::MyClass1(): t_member(new SomeClass) { }
 

main.cpp
Код
C++ (Qt)
#include "MyClass1.h"
#include "SomeClass.h"
 
int main()
{
MyClass1 class1;
class1.t_member->Fun<int>(111);
}
 

Никаких проблем!
« Последнее редактирование: Февраль 25, 2011, 03:34 от serg_hd » Записан

kubuntu/Win7/x64/NetBeans
Fat-Zer
Гость
« Ответ #14 : Февраль 25, 2011, 05:26 »

интересный способ заставить шаблон работать только с конкретными типами.

Ещё стандарт говорит о мистическом ключевом слове export, правда я не видел компилятор, который его поддерживает...
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.417 секунд. Запросов: 23.