Link question

F

firegun9

I am not a newbie C++, but I haven't coded multiple files project under
g++.
Here is my quesiont:

b.h
////////////////////
#ifndef b_h
#define b_h

class b{
int b1;
public:
b(){}
void set(int b1_);
};

void b::set(int b1_)
{
b1=b1_;
}

#endif




a.h
===========================
#include "b.h"

class a{
b* b_ptr;
public:
void set(b & b_obj);
};

void a::set(b & b_obj)
{
b_ptr=&b_obj;
}


main.cpp
////////////////////////////
#include "a.h"
#include "b.h"

int main()
{
a a_obj;
b b_obj;

a_obj.set(b_obj);

return 0;
}

For these 3 files, I can successfully compile and link by using "g++
main.cpp".
However, if I separate a.h into a.h and a.cpp, like here:
a.h
===========================
#include "b.h"

class a{
b* b_ptr;
public:
void set(b & b_obj);
};

a.cpp
/////////////////////////
#include "a.h"

void a::set(b & b_obj)
{
b_ptr=&b_obj;
}

then I use the command "g++ a.cpp main.cpp", I got a link error
"ld: fatal: symbol 'b::set(int)' is multiply-defined:
(file /var/tmp/ccUoZBm0.o type=FUNC; file /var/tmp/ccG0aQup.o
type=FUNC)"

and if I also separate b.h into b.h and b.cpp in the same way, the
error is gone.

What's going on here?
I just want to separate one of the files because in my real project,
there's only one .h file is so long.
 
V

Victor Bazarov

I am not a newbie C++, but I haven't coded multiple files project under
g++.
Here is my quesiont:

b.h
////////////////////
#ifndef b_h
#define b_h

class b{
int b1;
public:
b(){}
void set(int b1_);
};

void b::set(int b1_)

If you want to keep the _definitions_ of your functions in a header,
declare them 'inline', or define them in the class definition (where
they are 'inline' implicitly).
{
b1=b1_;
}

#endif




a.h
===========================
#include "b.h"

class a{
b* b_ptr;
public:
void set(b & b_obj);
};

void a::set(b & b_obj)
{
b_ptr=&b_obj;
}


main.cpp
////////////////////////////
#include "a.h"
#include "b.h"

int main()
{
a a_obj;
b b_obj;

a_obj.set(b_obj);

return 0;
}

For these 3 files, I can successfully compile and link by using "g++
main.cpp".
However, if I separate a.h into a.h and a.cpp, like here:
a.h
===========================
#include "b.h"

class a{
b* b_ptr;
public:
void set(b & b_obj);
};

a.cpp
/////////////////////////
#include "a.h"

void a::set(b & b_obj)
{
b_ptr=&b_obj;
}

then I use the command "g++ a.cpp main.cpp", I got a link error
"ld: fatal: symbol 'b::set(int)' is multiply-defined:
(file /var/tmp/ccUoZBm0.o type=FUNC; file /var/tmp/ccG0aQup.o
type=FUNC)"

and if I also separate b.h into b.h and b.cpp in the same way, the
error is gone.

What's going on here?

You're putting its definition in more than one module. No surprises.
I just want to separate one of the files because in my real project,
there's only one .h file is so long.

The number of '.h' files doesn't matter. What matters is in how many
'.cpp' files you're including it. Just think about it. What you do,
essentially, is duplicate all the code in all the files where you include
the header. '#include' directive is nothing but a text processing stunt.

V
 
F

firegun9

Well, I think I find the answer.

Every .o file will contain the implematitions of the files it included.
In my example, if I have 4 files, "b.h", "a.h", "a.cpp", "main.cpp",
there would be "a.o" and "main.o". Both of them will have the function
implementation writed in "b.h".( because they both can see "b.h") In
the linking stage, this would cause a duplicate definition problem when
the linker tries to link "a.o" and "main.o" together.

The solution to this is to split "b.h" into "b.h" and "b.cpp" in the
same way as "a.h".
In this way, the implementation of class b will be only in "b.o", "a.o"
and "main.o" will contain the information in "b.h" which is only the
declartion of class b. When the three objects are linked together, the
three object "b.o", "a.o" and "main.o" will contain the implementations
of theirselves.

Another workable situation is having "b.h", "b.cpp", "a.h" and
"main.cpp".
In this situation "b.o" contains class b's declaration and
implementation, "main.o" contains class b's declaration and class a's
declaration and implementation. Declarations can be overlapped in
different object files, however, implementation of each class would be
only appear once in corresponding object file.

To Victor:
Use inline for functions in class b is indeed work, but the reason is
not like that you say here. Inline function just tell the compiler to
append the definition of the function into where the function is being
called instead of go into the address of the function in the linking
stage which is the way how function is called in implementation of
functions in a .cpp file. The reason work in my example is because
there will be no implementation of class b in any .o object, so there's
no multiple-definition problem.

I may not be express very well in my poor English, if you have any
comments please feel free to send me.
 
V

Victor Bazarov

[...]
To Victor:
Use inline for functions in class b is indeed work, but the reason is
not like that you say here.

I don't say any reason.
Inline function just tell the compiler to
append the definition of the function into where the function is being
called instead of go into the address of the function in the linking
stage which is the way how function is called in implementation of
functions in a .cpp file. The reason work in my example is because
there will be no implementation of class b in any .o object, so there's
no multiple-definition problem.

That's not necessarily so. Inline functions are treated differently than
non-inline ones. It has to "merge" all the definitions of the same inline
function into one (or discard all but one, it doesn't matter, really).
Such operation ("merging" or "discarding") is not attempted for normal,
non-inline functions.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,701
Latest member
XavierQ83

Latest Threads

Top