g++ undefined reference in very simple example
Please help with the following noob question about C++ and g++ compilation and linking. Essentially I have 2 classes in 2 different files, and can compile them but when I attempt to link, one class can't see the methods of the other, even though I am linking both. Order of object files does not help in this case.
The problem seems related to a non-default constructor that takes a parameter.
I have distilled and reproduced the problem in the following simple code:
File: a.cpp:
#include <iostream>
class A
{
public:
int my_int;
A(int i) {
my_int = i;
std::cout << "A";
}
};
File: a.hpp:
#ifndef __A_H_
#define __A_H_
class A
{
public:
A(int i);
};
#endif
File b.cpp:
#include <iostream>
using namespace std;
#include <a.hpp>
class B
{
public:
int my_int;
B(int i) {
my_int = i;
A a(i);
cout << "B\n";
}
};
int main(int argc, char* argv[])
{
B b(5);
cout << "hello world: ";
cout.flush();
return 0;
}
Commands I use to build:
g++ -c -I. a.cpp
g++ -c -I. b.cpp
g++ -o c_test a.o b.o
Alternately, I've tried each of these:
g++ -o c_test b.o a.o
g++ -I. -o c_test a.cp开发者_C百科p b.cpp
g++ -I. -o c_test b.cpp a.cpp
Error I get in any of above link scenarios:
b.o: In function `B::B(int)':
b.cpp:(.text._ZN1BC1Ei[B::B(int)]+0x1c): undefined reference to `A::A(int)'
collect2: ld returned 1 exit status
Thanks in advance for any insight.
(sorry if this is a re-post -- I thought I posted it and don't see it...)
It doesn't work that way. What you've come across is technically an ODR violation, which roughly means that A
in both a.cpp
and b.cpp
must be the same thing. It isn't.
Moreover, the constructor is implicitly inline
in a.cpp and therefore its code needn't be emitted.
Changing a.cpp
to
#include <iostream>
#include "a.hpp"
A::A(int i) {
my_int = i;
std::cout << "A";
}
will fix the error.
You a.cpp
is violating the one definition rule and redefining A
entirely. You just want to define the function in your source file:
A::A(int i) {
my_int = i;
std::cout << "A";
}
Also you may want to mark the function explicit to avoid int
s being treated as A
's in a variety of unwanted contexts.
In a.cpp
, you should #include "a.hpp"
and then define the constructor simply as A::A(int i) { ... }
. By writing a whole definition of class A
with the constructor code within the class
body, you're implicitly defining the constructor as an inline function, which is why there's no definition for it in the object file.
You have two different classes (one containing myint
, one not) both called class A
. You can't do that. Change a.cpp
to:
#include <iostream>
#include "a.hpp"
A::A(int i) {
my_int = i;
std::cout << "A";
}
And change a.hpp
to:
#ifndef __A_H_
#define __A_H_
class A
{
public:
int my_int;
A(int i);
};
#endif
Thank about it, the way you have it, what would the compiler do if someone did this:
#include "a.hpp"
// ...
A foo(3);
cout << sizeof(foo) << endl;
How could it know that class A
has a member other than the constructor? How could it know the size?
You are breaking the One Definition Rule, as you have two distinct separate A
classes in your program. The simple common implementation of your A.cpp file should look like:
#include "a.h" // where the definition of the type is
A::A( int x ) : myint(i) {}
With "a.h" containing the proper definition of the type:
#ifndef A_H_ // identifiers containing double underscores (__) are reserved, don't use them
#define A_H_
class A
{
int myint; // This must be present in the definition of the class!
public:
A(int i);
};
#endif;
And then in the implementation of B, you probably meant:
#include "a.h"
#include <iostream>
using namespace std; // I don't like `using`, but if you use it, do it after all includes!
class B {
public:
// int my_int; // do you really want to hide A::my_int??
B(int i) : A(i) { // use the initializer list
cout << "B\n";
}
};
The right thing to do is:
a.hpp
#ifndef __A_H_
#define __A_H_
class A
{
public:
int my_int;
A(int i);
};
#endif
a.cpp
#include <iostream>
#include "a.hpp"
A::A(int i) {
my_int = i;
std::cout << "A";
}
b.cpp - remains the same
精彩评论