C++: функция заголовка неправильно подключена из библиотеки в exe

У меня есть файл заголовка в библиотеке (alibrary.lib). Библиотека является статической библиотекой (.lib) и она правильно ссылается на exe.

Теперь у меня есть класс: Vector3d.

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). После объявления класса я пересекаю функцию.

Компиляция lib - это файл, но когда он ссылается на 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

Есть идеи?

Спасибо

2 ответа

Решение

Если вы определяете свободную (не член класса) функцию, она должна быть определена в отдельно откомпилированном файле.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);

}

Ошибка вызвана тем, что у вас есть определение функции в заголовке, но вы не пометили ее как встроенную. Если вы теперь включите этот заголовок в два файла, которые скомпилированы отдельно, то компоновщик при попытке связать скомпилированные объектные файлы выдаст ошибку, потому что он увидит, что перекрестная функция определяется дважды.

Он работает без явного помещения inline для функций-членов класса, потому что функции-члены, которые определены внутри определения класса, неявно встроены.

Тем не менее, вообще не стоит делать определения функций в заголовке. Если ваша функция будет зависеть от других типов, чем просто вектор (в вашем случае это нормально ИМХО, но это спорно, конечно, - некоторые люди не любят это), то вам необходимо будет включать в себя заголовки для этих типов. Это излишне раздувает код, который косвенно включен в ваш заголовок. Вместо этого, в этих случаях вы бы поместили только объявление вашей функции внутри заголовка:

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, объявления классов, enum и так далее.

Определения (придающие смысл существующим вещам) - это такие вещи, как функции, различные определения и так далее.

Ваша перекрестная функция должна быть объявлена ​​в заголовочном файле:

Vector3d cross(const Vector3d &v0, const Vector3d &v1);

но определено в отдельном исходном файле.

Другие вопросы по тегам