С++:функция заголовка неправильно связывается из библиотеки в exe
-
20-08-2019 - |
Вопрос
У меня есть заголовочный файл в библиотеке (alibrary.lib).Библиотека является статической библиотекой (.lib) и правильно связана с exe.
Теперь у меня есть класс:Вектор3d.
class Vector3d
{
void amethod()
{
blah
}
};
Vector3d cross(const Vector3d &v0, const Vector3d &v1)
{
float x,y,z;
x = v0.y*v1.z-v0.z*v1.y;
y = v0.z*v1.x-v0.x*v1.z;
z = v0.x*v1.y-v0.y*v1.x;
return Vector3d(x,y,z);
}
Vector3d объявлен и определен в заголовочном файле (Vector3d .h).После объявления класса я использую кросс-функцию.
Компиляция библиотеки представляет собой файл, но когда она ссылается на exe-файл модульного теста, я получаю эту ошибку:
flywindow.obj :error LNK2005: "class Vector3d __cdecl cross(class Vector3d const &,class Vector3d const &)" (?cross@@YA?AVVector3d@@ABV1@0@Z) already defined in fly.obj
Есть идеи?
Спасибо
Решение
Если вы определяете свободную функцию (не член класса), ее необходимо определить в отдельно скомпилированном файле .cpp или в заголовке и пометить как встроенное.Итак, в вашем случае вы можете избежать компиляции следующим образом:
inline Vector3d cross(const Vector3d &v0, const Vector3d &v1) {
float x,y,z;
x = v0.y*v1.z-v0.z*v1.y;
y = v0.z*v1.x-v0.x*v1.z;
z = v0.x*v1.y-v0.y*v1.x;
return Vector3d(x,y,z);
}
Ошибка вызвана тем, что у вас есть определение функции в заголовке, но вы не пометили ее как встроенную.Если теперь вы включите этот заголовок в два файла, которые компилируются отдельно, компоновщик при попытке связать скомпилированные объектные файлы выдаст ошибку, поскольку тогда он увидит, что кросс-функция определяется дважды.
Он работает без явного встраивания функций-членов класса, поскольку функции-члены, определенные внутри определения класса, являются неявно встроенными.
Однако, как правило, не рекомендуется делать определения функций в заголовке.Если ваша функция будет зависеть от других типов, а не только от вектора (в вашем случае это нормально, ИМХО, но это, конечно, спорно - некоторым это не нравится), тогда вам потребуется включить заголовки для этих типов.Это приведет к излишнему раздуванию кода, косвенно включенного в ваш заголовок.Вместо этого в этих случаях вы должны поместить в заголовок только объявление вашей функции:
Vector3d cross(const Vector3d &v0, const Vector3d &v1);
Но определите его в файле .cpp, который скомпилирован отдельно.Встроенный, конечно, тогда следует отбросить.
Позвольте мне добавить небольшой список определений и объявлений, просто чтобы было понятнее, что означают объявления и определения для функций и классов.Обратите внимание, что каждое определение также является объявлением, но не наоборот:
// class _declaration_ of boo
class boo;
// class _definition_ of foo.
class foo {
// member function _declaration_ of bar
void bar();
// member function _definition_ of baz
void baz() { }
};
// function _definition_ of fuzz
inline void fuzz() { }
// function _declaration_ of fezz
void fezz();
Другие советы
Наиболее вероятное объяснение состоит в том, что у вас есть код (в частности, определение креста) в вашем включаемом файле, и ваш включаемый файл включается в два исходных файла, отсюда и двойное определение.
Заголовочные файлы должны содержать объявления, а не определения.Объявления (говорящие о том, что что-то существует) — это такие вещи, как typedef, объявления классов, перечисления и так далее.
Определения (придающие смысл существующим вещам) — это такие вещи, как функции, определения переменных и так далее.
Ваша кросс-функция должна быть объявлена в заголовочном файле:
Vector3d cross(const Vector3d &v0, const Vector3d &v1);
но определено в отдельном исходном файле.