c ++: функция заголовка неправильно подключена из библиотеки в exe - PullRequest
0 голосов
/ 01 февраля 2009

У меня есть заголовочный файл в библиотеке (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 ]

2 голосов
/ 01 февраля 2009

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

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();
1 голос
/ 01 февраля 2009

Наиболее вероятное объяснение состоит в том, что у вас есть код (в частности, определение креста) в вашем включаемом файле, и ваш включаемый файл включается двумя исходными файлами, отсюда и двойное определение.

Заголовочные файлы должны иметь объявления, а не определения. Объявления (если что-то существует) - это такие вещи, как typedef, объявления классов, enum и т. Д.

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...