undefined reference

basicly. I created the definition of a "rational" at rational.h and rational.cpp

I compiled it and got rational.o.

I then try to use the class in another .cpp file called test.cpp

I used #include "rational.h"

then i wrote rational r; in the main function.

But the compiler complains of undefined reference to `rational::rational()' which i clearly defined.

and I put those two files in the same folder. So now, i don't know how to "help" the test.cpp to "find" the definitions now.

the thing is, the book i'm learning from taught about this problem throughtout the chapters i was reading. But now i don't know what to do with this simple case.

my test.cpp is just this

#include <iostream>
#include "rational.h"

int main () {

rational::rational r;
return 0;
}




Thanks for your help.
Last edited on
Can I see the rational.h file?
Unless your rational type is part of a namespace called rational, you should declare r like this:

rational r;
to filipe: i tried that as well. didn't work. so that's probably not the problem

to firedraco: the file is below. I basicly copied it from the book i'm learning from
the compiler didn't complain when i compiled it with the rational.cpp file.


#include <string>
class rational {
public :
//constructors
rational ();
rational (int , int);
rational (const rational&);


//access
inline int numerator () const {return top;}
inline int denominator () const {return bottom;}
//assignment
void operator= (const rational&);
std::string str ();

private :
//data area
int top;
int bottom;

//internal operation
void rationalize();
};
First, you don't want the rational:: (since your rational is not inside a namespace).

Second, have you defined all of your functions in the rational.cpp file?
yeah, i did define all my functions in the rational.cpp file. I mostly just copied it from a book.

Could it be because i'm using code::block to compile it or sth? b/c i can't think of anything else. According to the book, everything should work out, then it doesn't. So frustrating.
i just got it to work by including a #include "rational.cpp" statement in my test.cpp program.

but i thought i just need to include the .h file.

am i supposed to include the rational.cpp file in the rational.h file??? Come to think of it, how else would the compiler now there is a rational.cpp file.

But somehow i don't remember the books ever doing it that way. They always write the .cpp, which include the header. but the header doesn't include the .cpp. and in the tester program, they include the .H file. This doesn't make any sense. is the compiler supposed to magically find the .cpp file?
Last edited on
You shouldn't include .cpp files. The header file should contain everything a user of the class will need.

how else would the compiler now there is a rational.cpp file.

The compiler will first compile each .cpp file separately. Header files will only compile if they're included in a .cpp file. Note that #include simply copies and pastes the included file into the .cpp file. At this stage, the compiler only checks that every identifier used is declared, but not necessarily defined.

After each unit is compiled into object code (they're called translation units) the linker will link the files. That's when it will need to find a definition for every identifier used.
ok, this is my understanding now.

after the compiler sees that the contents of rational.h.

it either 1) search for a rational.cpp file , which i think is pretty smart

2) compiles ALL the cpp files in the same folder, and look for the functions that need to be defined

(which doesn't seem smart, what if there's a thousand files in the same folder?)

3) but neither of the above makes sense, because i got errors if i don't include the .cpp. And further, i think it makes every logical sense to "directly lead" the compiler to find the .cpp file with the include. because, as you said, the include copies the file over, which is supposed to be the point of separating different parts of the program into different files.

why doesn't the .cpp get included manually, and instead we ask the compiler to search for it? this seems illogical and still magically to me.

thank you for your help, i'm new to this, and i find this very "simple (as the tone suggest in the books and tutorials) " concept very very confusing.
Last edited on
Well, it happens as I described it. If, say, rational.h is included in main.cpp, the compiler will not look at rational.cpp. The linker will look for the definitions of the functions described in rational.h in any of the translation units; it doesn't matter if they're implemented in a file called rational.cpp or foo.cpp or whatever.

Would you care to post your rational.cpp using [ code ] [ /code ] tags (without the spaces)?
according to the books, the following three files should work well. But right now i get the error message

C:\rational\testRational.o:testRational.cpp:(.text+0x13f)||undefined reference to `rational::rational(int, int)'|
||=== Build finished: 1 errors, 0 warnings ===|

rational.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef RATIONAL
#define RATIONAL

#include <string>

class rational {
     public :
	//constructors
	rational ();
	rational (int , int );
	rational (const rational&);


	//access
	inline int numerator () const {return top;}
	inline int denominator () const {return bottom;}
	//assignment
	void operator= (const rational&);
 	std::string str ();

     private :
	//data area
	int top;
	int bottom;

	//internal operation
    void rationalize();
};


#endif 


rational.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

#include "rational.h"
#include <string>
#include <sstream>

int abs (int n) {
	return (n>0) ? n : (-n); }

int gcd (int m, int n) {
	return (abs(n)==0) ? abs(m) : gcd(abs(n), abs(m)%abs(n));
}

rational::rational() : top(0), bottom(1){};

rational::rational(int numerator, int denominator) {
	assert(denominator!=0);
	top = numerator;
	bottom = denominator;
  	rationalize();
}

rational::rational(const rational & rat) : top(rat.numerator()), bottom(rat.denominator()) {
}

void rational::operator = (const rational & rat) {
	top = rat.numerator();
	bottom = rat.denominator();
}

 void rational::rationalize (){
	if (bottom<0) {
		bottom*=-1;
		top*=-1;
	}

	assert(bottom!=0);

    int d = gcd(top, bottom);
	top/=d;
	bottom/=d;
}

std::string rational::str () {
	std:: stringstream ss1;
	ss1 << top;

	if (bottom == 1)
		return ss1.str();

	std:: stringstream ss2;
	ss2 << bottom;
	return ss1.str() + "/" + ss2.str();
}


testrational.cpp
1
2
3
4
5
6
7
8
#include <iostream>
#include "rational.h"

int main () {

    rational r(2,4);
	return 0;
}
That code compiles for me...

EDIT: I did have to include assert.h, which I don't see included among your files.

Are those files part of the same project?
Last edited on
the assert shouldn't be the problem.

I just used dev-c++ to try to compile. didn't work either.

how do i "indicate" to the dev-c++ or code::block that the three files are in the same project? I thought it was enough that they be in the same folder.

EDIT: i got it to compile now in dev-c++ by adding them into the same project.

but i still want to learn the non-IDE way to do it. Can you recommend any compiler for windows that would do it?
Last edited on
Well, I'm not familiar with those IDEs, but in VC++ Express you would have an option to either create a project or a file.
Last edited on
sendjy wrote:
but i still want to learn the non-IDE way to do it. Can you recommend any compiler for windows that would do it?

Sorry, I really only have experience compiling through IDEs. I'm sure someone else can help, though.
Can you recommend any compiler for windows that would do it?


All of them can. (or at least all of them that are worth using).

The exact way to do this depends on what compiler you're using.

Assuming you're using GCC (a popular free compiler for many platforms, including Windows), you can skim this page: http://pages.cs.wisc.edu/~beechung/ref/gcc-intro.html

It has a simple example of how to do this:

1
2
3
  g++ -c testrational.cpp
  g++ -c rational.cpp
  g++ testrational.o rational.o -o myprogram


The first two lines run the compiler and compile each source file. This generates the .o object files.

The last line links the two object files together and produces the final binary.


But of course, you don't have to be a masochist. Just let the IDE do this crap.
Last edited on
to filipe: thanks, i thinking i'm getting the idea now.

to Disch: thank you soo much for your three line example. often, i can't think straight when i'm frustrated, and i don't know how long it would take me to figure out the proper way to compile and link the program. thank you again.
Topic archived. No new replies allowed.