web-dev-qa-db-fra.com

Déjà défini en .obj - pas de doubles inclusions

Il m'est arrivé d'obtenir ce déjà défini dans l'erreur .obj. C'est la structure de mon projet:

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

C'est ce que le compilateur se plaint:

main.obj: erreur LNK2005: "public: bool __thiscall SocketClient :: read (int, char *)" (? read @ SocketClient @@ QAE_NHPAD @ Z) déjà défini dans client.obj

Notez qu'il se plaint de ma classe, pas de boost. Une chose intéressante est que lorsque je supprime #include <boost/asio.hpp> de client.cpp , je reçois des erreurs thouhg il est aussi inclus dans main.h .

Comme vous pouvez le voir, je ne définis pas/y compris ma classe, elle est incluse exactement une fois dans main.h =. Alors qu'est-ce qui se passe ici?
J'ai lu cette réponse , mais cela ne m'a pas aidé, car il attend des doubles inclusions. Prenez ce fait en considération avant de voter pour un double, car cela signifie simplement me décapiter sans pitié.

25
Tomáš Zato

Ce n'est pas une erreur du compilateur : l'erreur provient de l'éditeur de liens . Après la compilation, l'éditeur de liens fusionnera les fichiers objets résultant de la compilation de chacune de vos unités de traduction (.cpp des dossiers).

L'éditeur de liens découvre que le même symbole est défini plusieurs fois dans différentes unités de traduction et s'en plaint (il s'agit d'une violation de la règle de définition unique).

La raison en est certainement que main.cpp comprend client.cpp, et ces deux fichiers sont traités individuellement par le compilateur pour produire deux fichiers objets séparés. Par conséquent, tous les symboles définis dans le client.cpp l'unité de traduction sera également définie dans le main.cpp unité de traduction. C'est l'une des raisons pour lesquelles vous n'avez généralement pas #include.cpp des dossiers.

Mettez la définition de votre classe dans un client.hpp fichier qui ne pas contient également les définitions des fonctions membres de cette classe; puis laissez client.cpp et main.cpp inclure ce fichier (je veux dire #include). Enfin, laissez dans client.cpp les définitions des fonctions membres de votre classe.

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"
41
Andy Prowl

Vous ne voulez probablement pas faire ceci:

#include "client.cpp"

Un fichier * .cpp aura été compilé par le compilateur dans le cadre de votre build. En l'incluant dans d'autres fichiers, il sera compilé à nouveau (et encore!) Dans chaque fichier dans lequel vous l'incluez.

Maintenant, voici la chose: Vous le gardez avec #ifndef SOCKET_CLIENT_CLASS, cependant, chaque fichier contenant #include "client.cpp"est construit indépendamment et comme tel trouvera SOCKET_CLIENT_CLASS pas encore défini. Par conséquent, son contenu sera inclus, et non # ifdef'd out.

S'il contient des définitions (plutôt que de simples déclarations), ces définitions seront répétées dans chaque fichier où il est inclus.

9