How to include header and cpp without resulting in LNK2005 error in Visual Studio

Asked

Viewed 315 times

1

The source code below is an abstraction of a code in production. However, it is real, and the facts reported below are applicable to it.

The code compiles usually in GCG (linux), but in Visual Studio 2017 (windows), I get the error:

LNK2005 "public: int __cdecl XTEST::Mt::soma(int,int)" (??soma@Mt@XTEST@@QEAHHH@Z) already defined in ...

main.cpp

#include "teste.cpp"
#include <stdio.h>

int main(){
    getchar();

    XTEST::Mt *t = new XTEST::Mt();

    printf("\n\nretorno = %d\n\n", t->soma(3, 5));

    delete t;

  return 0;
}

cpp testing.

#pragma once

#ifndef TESTE_H
#define TESTE_H

#include "mhead.cpp"

#endif

mhead. h

#pragma once

#ifndef MT_H
#define MT_H

namespace XTEST {
    class Mt {
    public:
        int soma(int i, int d);
    };
}

#endif

mhead.cpp

#pragma once

#ifndef MT_CPP
#define MT_CPP

#include "mhead.h"

namespace XTEST {
    int Mt::soma(int i, int d) {
        return i + d;
    }
}
#endif

I’m a beginner in C++ - especially VS - but I know that ". h" should not - preferably - contain implementations, only statements. Thus in the above case the ". h" contains only the class declaration, and the entire implementation is placed in the ". cpp".

You may wonder why I have the cpp testing.. This is because the program has a high amount of "modules". And in the program under production, all the features of a module are nested in a file ".cpp". These in turn must include the dependencies. Therefore, the existence of the "cpp testing." is to maintain the equivalence of this code with the real one, which was omitted because of the size (more than 10,000 lines).

This ends up making the implementation exists in the objects mhead.obj, obj test. and main obj., duplicate. As far as I know this is the reason for the above error.

However, it is impossible to compile a code without including the ".cpp" - which contains the implementations. How to include both the ".h" as to the ".cpp", allowing, however, the entire program to access the functionalities of the same?

NOTE: ". cpp" includes ". h" because ". cpp" demands the presence of the statements; however ". h" does not include ". cpp" because ". h" can make use of external implementation, such as ". dll".

Thank you.

EDITION 1:

The @lacobus answer is right (grateful) and solves the problem, but NOT conclusively. The above question includes the (implicit) need for GCC compilation, which may not have been clear, and the answer whether it had this objective was also unclear. A specific question for compatibility has been opened here.

1 answer

2

Avoid #include's of files that are not headers, this creates a "mess" without size!

It makes no sense to use #pragma once/#ifndef-#define in archives .cpp;

Do not mix #pragma once and #ifndef-#define, or one or the other.

OBS: Despite the directive #pragma once be supported by most compilers, it is not part of the standard and may not work in some cases.

Here’s an example (tested) illustrating something similar to what you’re trying to do:

Mt.cpp

#include "Mt.h"

namespace Subsistema {
    int Mt::soma(int i, int d) {
        return i + d;
    }
}

My.cpp

#include "My.h"

namespace Subsistema {
    int My::sub(int i, int d) {
        return i - d;
    }
}

Mx.cpp

#include "Mx.h"

namespace Subsistema {
    int Mx::mul(int i, int d) {
        return i * d;
    }
}

Mt. h

#ifndef MT_H
#define MT_H

namespace Subsistema {
    class Mt {
    public:
        int soma(int i, int d);
    };
}

#endif

My. h

#ifndef MY_H
#define MY_H

namespace Subsistema {
    class My {
    public:
        int sub(int i, int d);
    };
}

#endif

Mx. h

#ifndef MX_H
#define MX_H

namespace Subsistema {
    class Mx {
    public:
        int mul(int i, int d);
    };
}

#endif

Subsystem. h

#ifndef SUBSISTEMA_H
#define SUBSISTEMA_H

#include "Mt.h"
#include "Mx.h"
#include "My.h"

#endif

main.cpp:

#include <iostream>

#include "Subsistema.h"

int main(void)
{
    Subsistema::Mt * t = new Subsistema::Mt();
    Subsistema::Mx * x = new Subsistema::Mx();
    Subsistema::My * y = new Subsistema::My();

    std::cout << "Soma: " << t->soma(3, 5) << std::endl;
    std::cout << "Multiplicacao: " << x->mul(3, 5) << std::endl;
    std::cout << "Subtracao: " << y->sub(3, 5) << std::endl;

    delete t;
    delete x;
    delete y;

    return 0;
}

Exit:

Soma: 8
Multiplicacao: 15
Subtracao: -2
  • Thanks for your help. I realized that in no time is included the file ". cpp", this leads me to deduce that VS does the automatic inclusion of it. However, the doubt arises, how to avoid the "automatic" inclusion of ". cpp" by VS, when the wish is that implementations are imported from dll? I have used macros to automatically put "dllimport" before the functions. But if there is automatic inclusion of ". cpp", this would not generate redundancy?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.