Already defined object, where?

Started by
10 comments, last by rip-off 13 years, 1 month ago
I have been going over and over what could be wrong and I cannot figure out why I am getting these errors. Can someone please help me I have read MSDN, many many links but non of them help me out.

Errors

Error 1 error LNK2005: "class Foo Foo" (?Foo@@3V0@A) already defined in Bar.obj
Error 2 error LNK1169: one or more multiply defined symbols found


Bar.hpp

#ifndef _BAR_HPP
#define _BAR_HPP

class Foo
{
public:
Foo();
~Foo();
void SetInt(const int&);
int GetInt();
int var;
}Foo;

class Bar
{
public:
Bar(const int&);
~Bar();
int GetInt();
private:
};
#endif


Bar.cpp

#include "Bar.hpp"

Foo::Foo()
{
var = 0;
}
Foo::~Foo()
{
var = 0;
}
void Foo::SetInt(const int& value)
{
var = value;
}
int Foo::GetInt()
{
return var;
}

Bar::Bar(const int& value)
{
Foo.SetInt(value);
}
Bar::~Bar()
{
}
int Bar::GetInt()
{
return Foo.GetInt();
}


Main.cpp

#include <iostream>
#include "Bar.hpp"

using namespace std;

int main(int argc, char* argv[])
{
Bar bar(25);
cout << "Bar: " << bar.GetInt() << endl;

return 0;
}
Advertisement
Are you sure you want "} Foo;" instead of "};" at the end of your Foo class definition?
This looks like your problem:class Foo // defines a new class called Foo
{
...
}Foo;//Makes a new Foo object called Foo
The above is equivalent to:class Foo// defines a new class called Foo
{
...
};

Foo Foo;//Makes a new Foo object called Foo
The result of this is the every CPP file that includes "Bar.hpp", will create a new global variable called "Foo". Thus, both Main.cpp and Bar.cpp have global Foo objects, named Foo, and the linker is complaining that the global Foo object exists twice...
I was thinking of having a static class but not sure exactly how I would go about it. So I am trying this which works but it doesn't seem like it is the best method, any other ways that would be more efficient?

Bar.hpp

#ifndef _BAR_HPP
#define _BAR_HPP

namespace Foo
{
extern int var;
void SetInt(const int&);
int GetInt();
}

class Bar
{
public:
Bar(const int&);
~Bar();
int GetInt();
private:
};
#endif


Bar.cpp

#include "Bar.hpp"

namespace Foo
{
int var = 0;

void SetInt(const int& value)
{
var = value;
}
int Foo::GetInt()
{
return var;
}
}

Bar::Bar(const int& value)
{
Foo::SetInt(value);
}
Bar::~Bar()
{
}
int Bar::GetInt()
{
return Foo::GetInt();
}
C++ doesn't need static classes, it has free functions. You shouldn't need global mutable state. It is hard to propose good alternatives without a concrete example, but a typical approach is to wrap the shared data in a class to protect any invariants, and pass some kind of reference to an instance of this class to other classes that need it.

Note that your include guards clash with those reserved for the compiler. Using the shorter "BAR_HPP" form is safer (i.e. drop the leading underscores).

This looks like your problem:class Foo // defines a new class called Foo
{
...
}Foo;//Makes a new Foo object called Foo
The above is equivalent to:class Foo// defines a new class called Foo
{
...
};

Foo Foo;//Makes a new Foo object called Foo
The result of this is the every CPP file that includes "Bar.hpp", will create a new global variable called "Foo". Thus, both Main.cpp and Bar.cpp have global Foo objects, named Foo, and the linker is complaining that the global Foo object exists twice...



Hm... Not sure about that. Shouldn't the include guards prevent the linker from that??

[quote name='Hodgman' timestamp='1299648505' post='4783414']
This looks like your problem:class Foo // defines a new class called Foo
{
...
}Foo;//Makes a new Foo object called Foo
The above is equivalent to:class Foo// defines a new class called Foo
{
...
};

Foo Foo;//Makes a new Foo object called Foo
The result of this is the every CPP file that includes "Bar.hpp", will create a new global variable called "Foo". Thus, both Main.cpp and Bar.cpp have global Foo objects, named Foo, and the linker is complaining that the global Foo object exists twice...



Hm... Not sure about that. Shouldn't the include guards prevent the compiler about that??
[/quote]
Include guards don't reach across translation units; they only prevent the inclusion of headers multiple time within a single translation unit. They prevent the compiler from complaining about redefinitions, but it won't do anything about the linker complaining about multiple definitions.

[quote name='domUrob' timestamp='1299675594' post='4783526']
[quote name='Hodgman' timestamp='1299648505' post='4783414']
This looks like your problem:class Foo // defines a new class called Foo
{
...
}Foo;//Makes a new Foo object called Foo
The above is equivalent to:class Foo// defines a new class called Foo
{
...
};

Foo Foo;//Makes a new Foo object called Foo
The result of this is the every CPP file that includes "Bar.hpp", will create a new global variable called "Foo". Thus, both Main.cpp and Bar.cpp have global Foo objects, named Foo, and the linker is complaining that the global Foo object exists twice...



Hm... Not sure about that. Shouldn't the include guards prevent the compiler about that??
[/quote]
Include guards don't reach across translation units; they only prevent the inclusion of headers multiple time within a single translation unit. They prevent the compiler from complaining about redefinitions, but it won't do anything about the linker complaining about multiple definitions.
[/quote]

Thanks! That's the point! And then that's why the code is wrong. Since the header is declaring data instead of only defining types... You have the same global definition on each translation unit in which you include the header. There you have your linker screwed up.

The only way I see for this to be possible is to declare your Foo instance as static. Then it will only have scope inside each translation unit. But BE AWARE of the fact that there is a different instance for each time you include your header.

The namespace approach is already maximum performance :D, just as your "static class" would be.
I didn't even see the comment from the OP about efficiency. The most efficient solution is to avoid such data dependencies. It depends on the nature of the "var", what it is used for, how often it is used, the ratio of reads/writes and on a lot of other things.
Thanks for all the information the reason I am using this example is to spare the extreme amount of code in the actual program so I minimized it by using a Foo, Bar example. I did however resolve the issue after realizing it wasn't my code being complex but the fact that is was a basic problem I should have known about. In my real code I am using FMOD and what would be in the namespace Foo on my follow-up post would be the FMOD::system*, result, etc... stuff that doesn't need to be initialized more than once but is required to be used in a Music class and a Effect class, In all honesty I could probably modify it to be only one class, but there is a difference in loading a sound and a stream, even though multiple file formats could be loaded either way.


C++ doesn't need static classes, it has free functions. You shouldn't need global mutable state. It is hard to propose good alternatives without a concrete example, but a typical approach is to wrap the shared data in a class to protect any invariants, and pass some kind of reference to an instance of this class to other classes that need it.

Note that your include guards clash with those reserved for the compiler. Using the shorter "BAR_HPP" form is safer (i.e. drop the leading underscores).
[/quote]

Just curious if C++ doesn't need static classes, why does cplusplus.com have an example on the usage of "static"? Is that site wrong for showing a use of something not needed in that specific language? Also thanks for the tip on the '_' So many bad examples out there a long the learning road. I have really disconnected from tutorial sites though over time as I have noticed a lot of bad practices a long the way, but only after I look back. The site Cplusplus.com isn't in that mix since they are not tutorials really, just example usage in the basic.

This topic is closed to new replies.

Advertisement