3

I'm new to using header files and such, last semester we did everything in one giant(horrible :p) file ...

Am I doing something I'm not supposed to? Attempting to run the program results in the following:

1>  LINK : ~~~\CSC 161\Accounting Assignment\Debug\Accounting Assignment.exe not found or not built by the last incremental link; performing full link
1>driver.obj : error LNK2005: "class std::basic_ifstream<char,struct std::char_traits<char> > welcomeFile" (?welcomeFile@@3V?$basic_ifstream@DU?$char_traits@D@std@@@std@@A) already defined in statistics.obj
1>~~~~\CSC 161\Accounting Assignment\Debug\Accounting Assignment.exe : fatal error LNK1169: one or more multiply defined symbols found
1>

statistics.h:

#ifndef _STATISTICS_INTERFACE_
#define _STATISTICS_INTERFACE_
...
#include<fstream>

using namespace std;
ifstream  welcomeFile;   //if I comment this out, it compiles

class Stats
{
...blah...
};

void welcome();
void pause();
void printFile(ifstream &inFile);

#endif

statistics.cpp:

#include "statistics.h"

...working functions...

void welcome()
{
    system("CLS");
    welcomeFile.open("about.txt");
    printFile(welcomeFile);
    welcomeFile.close();
    pause();
}

The errors look like something is trying to be defined twice, but I thought #ifndef was supposed to set it so it only defined things if they weren't already? This is the only place where I declared welcomeFile ...

Daniel B.
  • 1,220
  • 14
  • 33

2 Answers2

6

Because you defined the object in the header file and violated one definition rule.

Never define objects in header file!

Header guards prevent the contents of the header to be included multiple times in the same translation unit during preprocessing. They do not prevent the contents to be included in different translation units. When you include this header file in different translation units, each of these units will have a definition of this object.
The compiler compiles each translation unit separately to produce a separate object file(.o), each of those .o files will have an copy of this object definition. When the linker tries to link to the object/symbol name at time of generating the .exe it finds multiple definitions of the same object/symbol, thereby causing confusion as to which one to link to. To avoid this problem the standard defines a rule known as the One defintion rule(ODR), which forbids multiple definitions of the same entity.
As you see including the object definition in the header file and including that header file in multiple translation units violates the ODR.

If you want to use a global object, You need to declare it as extern and define it in one and only one source file.

Good Read:
error LNK2005, already defined?

Community
  • 1
  • 1
Alok Save
  • 190,255
  • 43
  • 403
  • 518
  • Oh. Well. I guess I'm misunderstanding then, and should feel foolish. What about the ones in the class (which are not shown?) What's the difference? – Daniel B. Jan 25 '13 at 05:56
  • 1
    @DanielBall: I guess you mean class members, class members are **declared** in the class body **not defined**. What you have is definition not declaration. [Good read](http://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration) – Alok Save Jan 25 '13 at 06:00
  • Alok, you are a scholar and a gentleman; that was a very well written and sourced answer and I understand MUCH better now, thank you so much! – Daniel B. Jan 25 '13 at 06:02
  • @DanielBall: Thank you and glad it helped :) – Alok Save Jan 25 '13 at 06:04
2

You should put that definition in a .cpp file. Otherwise, every file that includes this .h file will have a definition of this variable, which ultimately clash during linking.

p.s. putting using namespace std; in your header, is considered bad.

Community
  • 1
  • 1
Karthik T
  • 29,587
  • 4
  • 58
  • 84
  • I think I see what you mean ... that post makes it sound more like using namespaces at all would be a bad idea? What about using typedefs in the header for the functions I need from the namespace, i.e. typedef std::string string; ? – Daniel B. Jan 26 '13 at 05:45
  • @DanielBall `using namespace std` as a blanket is kinda messy but it amplifies when used in a `.h` because it would be included in many `.cpp` files. `typedef is hacky, but just `using std::string` will do what you want, as explained in http://stackoverflow.com/a/1453630/1520364 – Karthik T Jan 26 '13 at 09:20
  • But that post discourages even that in the header.. so its up to you. – Karthik T Jan 26 '13 at 09:22
  • Well, thanks for the input. It's not crucial for a school project, but it's never too soon to avoid a bad habit right? – Daniel B. Jan 26 '13 at 19:17