0

Inside General.h

#ifndef GENERAL
#define GENERAL
namespace counternamespace{
    int upperbound;
    int lowerbound;
}
#endif

Inside Analyzer.h

#ifndef ANALYZER
#define ANALYZER
#include"General.h"

class Analyzer
{
public :
     int var ;
     int func();
};
#endif

Inside Test.h

#ifndef TEST
#define TEST
#include"Analyzer.h" //Error
class Test2
{
public:
    Test2(void);

public:
    ~Test2(void);
};
#endif

In the above code when I don't add Analyzer inside Test.h everything is working fine. But after adding its showing the following linker error.

1>Test2.obj : error LNK2005: "int counternamespace::lowerbound" (?lowerbound@counternamespace@@3HA) already defined in Analyzer.obj
2>Test2.obj : error LNK2005: "int counternamespace::upperbound" (?upperbound@counternamespace@@3HA) already defined in Analyzer.obj

I have added the #ifndef/#endif. Then where I am doing the mistake? Can anyone please let me know?

Viku
  • 2,845
  • 4
  • 35
  • 63

3 Answers3

2

Yeah, Alok has right. You presumably have Analyser.cpp and Test2.cpp, both are different compilation units. When you call

g++ Analyser.cpp Test2.cpp

the compiler actually makes Analyser.obj and Test2.obj separately and links them together. When the compiler tries to link Analyser.obj and Test2.obj together it realises that the two variables in Test2.obj are present in Analyser.obj too.

Your #define directives do not work since they are present only in a single compilation unit, so General.h is included both in Analyser.obj and Test2.obj.

To avoid such duplicates, the solution is wrapping your namespace variables around with a function. It goes like this:

Inside General.h

#ifndef GENERAL
#define GENERAL
namespace counternamespace{
    int& upperbound();
    int& lowerbound();
}
#endif

inside General.cpp

#include "General.h"
namespace counternamespace{
  int& upperbound(){static int local; return local;}
  int& lowerbound(){static int local; return local;}
}

So you can say now

counternamespace::upperbound()=3;
counternamespace::lowerbound()=1;

and it means the same as you would have said

counternamespace::upperbound = 3;
counternamespace::lowerbound = 1;

don't worry, the compiler will optimise away the function call so there is no overhead either.

Community
  • 1
  • 1
Barney Szabolcs
  • 11,846
  • 12
  • 66
  • 91
  • Thanks the error is gone now . But how can i access the counternamespace inside Analyzer .I am not able to access counternamespace now . – Viku Dec 31 '12 at 11:28
  • 1
    @Learner: You access `counternamespace` just like before. Nothing has changed, except for the additional parentheses after `upperbound` and `lowerbound`. – Bart van Ingen Schenau Dec 31 '12 at 12:16
1

You should not define any variables in header files.
A copy of the variables gets created in each translation unit When you include the header file in other files, thus violating the one definition rule and resulting in linking errors.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • :Ok . Leave about Test2.h file . Inside Analyzer.h too General .h has been included . So in this case there shall be some linker error because of namespace definition both inside Analyzer and General translation unit . But its not showing any linker error . Can you please clarify on this ? – Viku Dec 31 '12 at 10:37
  • @Learner You have Analyser.cpp and Test2.cpp, both are different compilation units. – Barney Szabolcs Dec 31 '12 at 10:42
  • 1
    I've added details on this and a solution into my answer. – Barney Szabolcs Dec 31 '12 at 10:52
1
Inside General.h

#ifndef GENERAL
#define GENERAL
namespace counternamespace{
    extern int upperbound;
    extern int lowerbound;
}
#endif

Inside General.cpp

#include"General.h"
using namespace counternamespace ;
int counternamepace::upperbound = 12;
int counternamepace::lowerbound = 12;

Then do whatever needed .

Viku
  • 2,845
  • 4
  • 35
  • 63