c++ - Como incluir header e cpp sem resultar em erro LNK2005 no Visual Studio - Stack Overflow em Português
O código fonte abaixo é uma abstração de um código em produção. Porém é real, e os fatos relatados adiante são aplicáveis ao mesmo.
O código compila normalmente em GCG (linux), porém no Visual Studio 2017 (windows), recebo o erro:
LNK2005 "public: int __cdecl XTEST::Mt::soma(int,int)" (?soma@Mt@XTEST@@QEAAHHH@Z) já definida no ...
#include "teste.cpp"
XTEST::Mt *t = new XTEST::Mt();
printf("\n\nretorno = %d\n\n", t->soma(3, 5));
#include "mhead.cpp"
mhead.h
namespace XTEST {
mhead.cpp
#ifndef MT_CPP
#define MT_CPP
#include "mhead.h"
Sou iniciante em C++ - especialmente em VS - mas sei que ".h" não deve - preferencialmente - conter implementações, somente declarações. Assim no caso acima o ".h" contém apenas a declaração da classe, sendo toda a implementação colocada no ".cpp".
Você pode se perguntar porque tenho o teste.cpp. Isso ocorre porque o programa possui elevada quantidade de "módulos". E no programa em produção, todas as funcionalidades de um módulo estão aninhadas em um arquivo ".cpp". Estes por sua vez devem incluir as dependências. Portanto, a existência do "teste.cpp" é para manter a equivalência deste código com o verdadeiro, que foi omitido por causa do tamanho (mais de 10.000 linhas).
Isso acaba por fazer que a implementação exista nos objetos mhead.obj, teste.obj e main.obj, duplicadamente. Até onde eu sei este é o motivo para o erro acima.
Porém, é impossível compilar um código sem incluir o ".cpp" - que contém as implementações. Como incluir tanto o ".h" quanto o ".cpp", permitindo porém, que todo o programa tenha acesso as funcionalidades do mesmo?
NOTA: O ".cpp" inclui o ".h", porque o ".cpp" exige a presença das declarações; porém o ".h" não inclui o ".cpp" porque o ".h" pode fazer uso de implementação externa, tais como ".dll".
A resposta @lacobus está certa (grato) e resolve o problema, mas NÃO de maneira conclusiva. A pergunta supra, inclui a necessidade (implícita) de compilação em GCC, o que pode não ter ficado claro, e a resposta se teve esse objetivo também não ficou clara. Uma pergunta especifica para compatibilidade foi aberta aqui.
editada 5/10/2017 às 1:59
perguntada 1/10/2017 às 5:30
Evite #include's de arquivos que não sejam headers, isso cria uma "bagunça" sem tamanho!
Não faz sentido usar #pragma once/#ifndef-#define em arquivos .cpp;
Não misture #pragma once e #ifndef-#define, ou um, ou outro.
OBS: Apesar da diretiva #pragma once ser suportado pela maioria dos compiladores, ela não faz parte do padrão e pode não funcionar em alguns casos.
Segue um exemplo (testado) ilustrando algo semelhante ao que você está tentando fazer:
int My::sub(int i, int d) {
return i - d;
Mx.cpp
int Mx::mul(int i, int d) {
int sub(int i, int d);
#ifndef MX_H
#define MX_H
int mul(int i, int d);
Subsistema.h
#ifndef SUBSISTEMA_H
#define SUBSISTEMA_H
#include "Subsistema.h"
Subsistema::Mx * x = new Subsistema::Mx();
Subsistema::My * y = new Subsistema::My();
std::cout << "Multiplicacao: " << x->mul(3, 5) << std::endl;
std::cout << "Subtracao: " << y->sub(3, 5) << std::endl;
Multiplicacao: 15
Subtracao: -2
respondida 1/10/2017 às 11:04
Obrigado por sua ajuda. Percebi que em nenhum momento é incluído o arquivo ".cpp", isso me leva a deduzir que o VS faz a inclusão automática dos mesmo. Porém, surge a dúvida, como evitar a inclusão "automática" dos ".cpp" pelo VS, quando o desejo for que as implementações sejam importadas de dll? Eu tenho usado macros para colocar automaticamente "dllimport" antes das funções. Mas se houver inclusão automática dos ".cpp", isso não geraria redundância?