C++ header cannot be included without LNK2005 error

118 views Asked by At

I have a large project which is designed to control and test hardware.

There are 4 device control classes (for interferometers, a piezo-motor, a PXI system, and a nano-positioning controller).

I created a "master" class called MainIO which stores an instance of each of the above classes, in order to perform operations across the range of IO (i.e. move motor and check interferometers). The MainIO header file includes the 4 control classes headers.

I then have a separate "global" hpp/cpp which contains global variables, conversions, ini file operations and so on. This is laid out with namespaces for the types of operation rather than creating a class, i.e. GCONV::someFunction(); and GMAIN::controllerModel;

I need all 4 control classes to have access to conversion and other global operations. I had them all including global.hpp at one point, but I've changed something (I can't think what it could be!) and now it seems that I cannot include global.hpp in ANY of my control class hpp's or cpp's without getting a linker error -

global.obj:-1: error: LNK2005: "class QString GMAIN::controllerModel" (?controllerModel@GMAIN@@3VQString@@A) already defined in controllers.obj

I'm absolutely certain that I've done something stupid and the solution is staring me in the face, but it's got to the stage where I'm getting so frustrated with it that I cannot see the wood for the trees.

3

There are 3 answers

0
Anil Solanki On

You should export your dll. Use __declspec(dllexport). You can include __declspec(dllexport) as a macro in your header file and put the macro in the beginning of each and every member function.

For example: In your Header.h file include

#define MYMACRO __declspec(dllexport);

and in your class

class classname
{
  public:
  MYMACRO void MYFUNCTION();
  MYMACRO void MYFUNCTION2();
};
1
Tony Park On

Are you defining controllerModel where you should only be declaring it? http://www.cprogramming.com/declare_vs_define.html

0
Sam Frost On

I have discovered what I was doing wrong, and although it is frustratingly simple, it took me a while to find the relevant documentation to discover my error, and so I will answer my own question in the hope of giving someone else an easier time.

It turns out that in global.hpp I was declaring variables within a namespace like this:

namespace GMAIN {
    QString controllerModel;
}

Essentially this means that every file that includes global.hpp will include its own definition of QString controllerModel thereby throwing the linker error. Each control class would have its own definition of the same named variable, violating the one definition rule.

To fix this, QString controllerModel needs to be extern'ed. The extern keyword allows a variable to be declared in multiple locations while only having a single definition (and hence not breaking the rule).

So the working code is now:

//in global.hpp
namespace GMAIN {
    extern QString controllerModel; //declaration - this is called for each `#include global.hpp`
}

//in global.cpp
namespace GMAIN {
    QString controllerModel; //definition - only called once as .cpp is never included
}