Уже определено в .obj - нет двойных включений
Мне удалось получить то, что уже определено в ошибке .obj. Это структура моего проекта:
main.cpp
#include "main.h";
main.h
#include <iostream>
#include <string>
#include <sstream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include "client.cpp"
client.cpp
#ifndef SOCKET_CLIENT_CLASS
#define SOCKET_CLIENT_CLASS
#ifndef BOOST_ASIO_HPP
#include <boost/asio.hpp>
#endif
/*CLASS DEFINITION HERE*/
#endif
Об этом жалуется компилятор:
main.obj: ошибка LNK2005: "public: bool __thiscall SocketClient:: read (int, char *)" (? read @SocketClient @@QAE_NHPAD @Z) уже в client.obj
Обратите внимание, что он жалуется на мой класс, а не на повышение. Интересно то, что когда я удаляю #include <boost/asio.hpp>
из client.cpp, я получаю ошибки, которые вы включаете в main.h тоже.
Как вы можете видеть, я не дважды определяю/включая мой класс, его включал ровно один раз в main.h. Итак, что здесь происходит?
Я прочитал этот ответ, но это не помогло, так как оно предполагает двойные включения. Возьмите этот факт в оглавление перед голосованием за дублирование, потому что это просто означает обезглавить меня без пощады.
Ответы
Ответ 1
Это не ошибка компилятора: ошибка возникает из компоновщика. После компиляции компоновщик объединит объектные файлы, полученные в результате компиляции каждого из ваших единиц перевода (.cpp
файлов).
Компонент узнает, что у вас есть один и тот же символ, определенный несколько раз в разных единицах перевода, и жалуется на него (это нарушение правила одного определения).
Причина, безусловно, в том, что main.cpp
включает client.cpp
, и оба эти файла обрабатываются отдельно компилятором для создания двух отдельных объектных файлов. Поэтому все символы, определенные в блоке трансляции client.cpp
, будут также определены в блоке перевода main.cpp
. Это одна из причин, по которой вы обычно не делаете файлы #include
.cpp
.
Поместите определение вашего класса в отдельный файл client.hpp
, в котором не содержит также определения функций-членов этого класса; то пусть client.cpp
и main.cpp
включают этот файл (я имею в виду #include
). Наконец, оставьте в client.cpp
определения функций вашего класса.
client.h
#ifndef SOCKET_CLIENT_CLASS
#define SOCKET_CLIENT_CLASS
#ifndef BOOST_ASIO_HPP
#include <boost/asio.hpp>
#endif
class SocketClient // Or whatever the name is...
{
// ...
bool read(int, char*); // Or whatever the name is...
// ...
};
#endif
client.cpp
#include "Client.h"
// ...
bool SocketClient::read(int, char*)
{
// Implementation goes here...
}
// ... (add the definitions for all other member functions)
main.h
#include <iostream>
#include <string>
#include <sstream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include "client.h"
// ^^ Notice this!
main.cpp
#include "main.h"
Ответ 2
Вероятно, вы не хотите этого делать:
#include "client.cpp"
Файл A *.cpp будет скомпилирован компилятором как часть вашей сборки. Включив его в другие файлы, он будет скомпилирован снова (и снова!) В каждом файле, в который вы его включаете.
Теперь вот что: вы охраняете его с помощью #ifndef SOCKET_CLIENT_CLASS
, однако каждый файл с #include "client.cpp"
создается независимо и как таковой найдет SOCKET_CLIENT_CLASS
еще не определен. Поэтому содержимое будет включено, а не # ifdef'd.
Если он содержит какие-либо определения вообще (а не просто объявления), то эти определения будут повторяться в каждом файле, в который он был включен.
Ответ 3
Это один из способов преодоления этой проблемы.
-
Просто поставьте прототип в файлы заголовков и включите файлы заголовков в .cpp файлы, как показано ниже.
client.cpp
ifndef SOCKET_CLIENT_CLASS
определить SOCKET_CLIENT_CLASS
ifndef BOOST_ASIO_HPP
включить
ENDIF
class SocketClient//Или независимо от имени... {
//...
bool read(int, char*); // Or whatever the name is...
//...};
ENDIF
client.h
bool SocketClient::read(int, char*)
{
// Implementation goes here...
}
main.cpp
#include <iostream>
#include <string>
#include <sstream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include "client.h"
// ^^ Notice this!
main.h
int main()