I have the file long_arithm.cpp:
#ifndef LONG_ARITHM.CPP
#define LONG_ARITHM.CPP
#include <iostream>
#include <list>
namespace long_arithm {
typedef signed char schar;
enum { error_char = 127 };
class longint {
public:
longint() : minusSign(0), array() { }
longint(int num) { fromInt(num); }
longint(std::string str) { fromString(str); }
longint(const longint& other) : minusSign(other.minusSign), array(other.array) { }
void fromInt(int num);
void fromString(std::string str);
protected:
schar digtochar(schar num);
schar chartodig(schar ch);
inline bool isDigit(schar ch) { /* code */ }
inline bool isSpaceChar(schar ch) { /* code */ }
private:
bool minusSign;
std::list<schar> array;
};
};
void long_arithm::longint::fromInt(int num) {
/* code */
}
void long_arithm::longint::fromString(std::string str) {
/* code */
long_arithm::schar long_arithm::longint::digtochar(schar num) {
/* code */
}
long_arithm::schar long_arithm::longint::chartodig(schar ch) {
/* code */
}
#endif
Now I'm trying build it, but I have errors (1st and 2nd lines - Eclipce header):
Building target: long_arithmetics
Invoking: Cross G++ Linker
g++ -o "long_arithmetics" ./long_arithm.o ./main.o
./main.o: In function `long_arithm::longint::fromInt(int)':
/home/gxoptg/Документы/My works/Developing/C++/long_arithmetics/Debug/../long_arithm.cpp:153: multiple definition of `long_arithm::longint::fromInt(int)'
./long_arithm.o:/home/gxoptg/Документы/My works/Developing/C++/long_arithmetics/Debug/../long_arithm.cpp:153: first defined here
./main.o: In function `long_arithm::longint::fromString(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
/home/gxoptg/Документы/My works/Developing/C++/long_arithmetics/Debug/../long_arithm.cpp:168: multiple definition of `long_arithm::longint::fromString(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
./long_arithm.o:/home/gxoptg/Документы/My works/Developing/C++/long_arithmetics/Debug/../long_arithm.cpp:168: first defined here
./main.o: In function `long_arithm::longint::chartodig(signed char)':
/home/gxoptg/Документы/My works/Developing/C++/long_arithmetics/Debug/../long_arithm.cpp:204: multiple definition of `long_arithm::longint::chartodig(signed char)'
./long_arithm.o:/home/gxoptg/Документы/My works/Developing/C++/long_arithmetics/Debug/../long_arithm.cpp:204: first defined here
./main.o: In function `long_arithm::longint::digtochar(signed char)':
/home/gxoptg/Документы/My works/Developing/C++/long_arithmetics/Debug/../long_arithm.cpp:188: multiple definition of `long_arithm::longint::digtochar(signed char)'
./long_arithm.o:/home/gxoptg/Документы/My works/Developing/C++/long_arithmetics/Debug/../long_arithm.cpp:188: first defined here
(Note, the line links (like :188) are broken, because I threw out a lot of commented lines of code.)
Why I have that errors and what I should correct? As good as I understand,
void fromInt(int num);
and others are 'pre-definitions', and I don't see any other definitions of that methods.
Thank you for help.
The functions that are defined outside of the class definition must either be moved to a source (.cpp) file or you must use the inline keyword at the front of them. Otherwise a copy of the function is placed into each source file that includes the header and marked as available to other modules, and the linker complains when there's more than one.
You say you included long_arithm.cpp in main. But you also compile it separately and then try to link the result with main.o. That's what causes the duplicates.
Looks like you didn't close the namespace definition and used its name inside the namespace for qualifying the function names, while defining them inside. Including this .cpp file inside other files may cause multiple definitions to occur inside different .cpp files, which cause the aforementioned problem.
Related
I'm reading the book "a complete guide to c++". I think there is a typo there on page 252. So I have three files as the following.
In file account.h,
// account.h
// Defining the class Account. class definition (methods prototypes) is usually put in the header file
// ---------------------------------------------------
#ifndef _ACCOUNT_ // if _ACCOUNT_ is not defined
#define _ACCOUNT_
#include <iostream>
#include <string>
using namespace std;
class Account
{
private:
string name;
unsigned long nr;
double balance;
public: //Public interface:
bool init( const string&, unsigned long, double);
void display();
};
#endif
// _ACCOUNT_
In file account.cpp,
// account.cpp
// Defines methods init() and display().
// ---------------------------------------------------
#include "account.h" // Class definition
#include <iostream>
#include <iomanip>
using namespace std;
// The method init() copies the given arguments
// into the private members of the class.
bool Account::init(const string& i_name,
unsigned long i_nr,
double i_balance)
{
if( i_name.size() < 1)
return false; // check data format to make sure it is valid
name = i_name;
nr = i_nr;
balance = i_balance;
return true;
}
// the method display() outputs private data.
void Account::display()
{
cout << fixed << setprecision(2)
<< "--------------------------------------\n"
<< "Account holder:" << name << '\n'
<< "Account number:" << nr << '\n'
<< "Account balance:" << balance << '\n'
<< "--------------------------------------\n"
<< endl;
}
And finally, in file account_t.cpp
// account_t.cpp
// Uses objects of class Account.
// ---------------------------------------------------
#include "account.h" // header file which contains class definition; (prototype for member functions)
int main()
{
Account current1, current2; // create two instances with name current1, current2
current1.init("Cheers, Mary", 1234567, -1200.99);
// have to call the init function to initialize a Account object; init function is public; members properties are private;
// that's why can not do current1.name = "nana" outside of the class definition
current1.display();
// current1.balance += 100; // Error: private member
current2 = current1;
current2.display();
current2.init("Jones, Tom", 3512347, 199.40);
current2.display();
Account& mtr = current1; // create a reference, which points to object current1
mtr.display();
return 0;
}
I do not think it's correct; because obviously there is no way to get access the init member methods and the display member methods, right? I hope this is not a naive question.
EDIT: I tried to run the main function in file account_t.cpp, and got the following output.
~$ g++ account_t.cpp
/tmp/ccSWLo5v.o: In function `main':
account_t.cpp:(.text+0x8c): undefined reference to `Account::init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long, double)'
account_t.cpp:(.text+0xb6): undefined reference to `Account::display()'
account_t.cpp:(.text+0xd5): undefined reference to `Account::display()'
account_t.cpp:(.text+0x132): undefined reference to `Account::init(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long, double)'
account_t.cpp:(.text+0x15c): undefined reference to `Account::display()'
account_t.cpp:(.text+0x176): undefined reference to `Account::display()'
collect2: error: ld returned 1 exit status
Any more comments are greatly appreciated.
There is no issue with what you are asking about. init and display are declared public in the definition of class Account and the file with the class definition is #includeed properly in the .cpp using these methods.
In order to use a function only its declaration is needed (which is in the class definition in the header which is included). The definition/implementation in the .cpp file is not needed to use the function.
Each .cpp is compiled individually (called a translation unit) and afterwards each use of a function (for which only the declaration might have been available) is linked to the correct definitions from the other translation units if necessary via the function's scope, name and signature. This is called the linking process.
An introductory book to C++ should explain how compilation and linking process work.
For g++, there is an easy way to compile all .cpp files individually as translation units and then directly link them together:
g++ account_t.cpp account.cpp
You always need to add all .cpp to the compiler invocation like that. (There are alternative ways, but this is the easiest one.)
However, as mentioned in the comments there are other issues with this program:
_ACCOUNT_ is a reserved identifier that one may not #define in a program. All identifiers starting with an underscore followed by a capital letter are reserved. Using them causes undefined behavior.
using namespace std; is bad, at the very least when used in a header file, see Why is "using namespace std;" considered bad practice?.
Classes have constructors. One should not write init methods in most cases. The constructor is responsible for constructing and initializing class instances. But no constructor is used in the code.
Money should never be stored in double, because arithmetic with double is imprecise. You should store the value in an integer type in dimensions of the smallest relevant unit of money (e.g. cents).
#include <iostream> is not needed in the header file. One should avoid adding #includes that are not needed.
init returns a boolean indicating successful initialization. But main never checks that value. If a function can fail with an error value, then you must check that error value returned by the function to make sure that continuing the rest of the program is safe.
Some of these points may be excusable as simplification for a beginner program, depending on how far the book got at this point (though 200+ pages should already cover a lot), but others aren't.
Example of constructor use doing the same thing:
class Account
{
private:
string name;
unsigned long nr;
double balance;
public: //Public interface:
Account(const string&, unsigned long, double);
void display();
};
Account::Account(const string& i_name,
unsigned long i_nr,
double i_balance)
: name(i_name), nr(i_nr), balance(i_balance)
{
}
int main()
{
Account current1("Cheers, Mary", 1234567, -1200.99);
// Create Account instance and initialize private members; constructor is public; members properties are private;
// that's why can not do current1.name = "nana" outside of the class definition
current1.display();
// current1.balance += 100; // Error: private member
Account current2 = current1; // Create second Account instance and copy private members from first one
current2.display();
current2 = Account("Jones, Tom", 3512347, 199.40); // Replace instance with a copy of a new one
current2.display();
Account& mtr = current1; // create a reference, which points to object current1
mtr.display();
return 0;
}
The i_name.size() < 1 check (which is weirdly written, why not i_name.size() == 0?) would be realized by throwing an exception from the constructor:
Account::Account(const string& i_name,
unsigned long i_nr,
double i_balance)
: name(i_name), nr(i_nr), balance(i_balance)
{
if(i_name.size() == 0) {
throw invalid_argument("Account does not accept empty names!");
}
}
This requires #include<stdexcept> and is a more advanced topic.
I encountered this problem when I try to compile my code
I thought it might be caused by header files including each other. But as far as I can tell I did not find any issues with my header files
Error LNK1169 one or more multiply defined symbols
found Homework2 D:\05Development\04 C_C++\C\DS Alg
class\Homework2\Debug\Homework2.exe 1
also, there's an error telling me that function Assert() has been declared elsewhere.
Error LNK2005 "void __cdecl Assert(bool,class
std::basic_string,class
std::allocator >)"
(?Assert##YAX_NV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z)
already defined in DataBase.obj Homework2 D:\05Development\04
C_C++\C\DS Alg class\Homework2\Homework2\dbTest.obj 1
here's the structure of my code:
function
void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
is in Constants.h
A virtual class List includes Constants.h
#pragma once // List.h
#include "Constants.h"
An array list includes List class, in the AList class it calls the Assert function
#pragma once //AList.h
#include "List.h"
...
Assert((pos >= 0) && (pos < listSize), "Position out of range");
In the DataBase class I created a AList member
private:
AList<CData> set;
header looks like this:
#pragma once
#include "AList.h"
#include "CData.h"
and CData.h looks like this:
#pragma once
class CData
{
private:
std::string m_name;
int m_x;
int m_y;
public:
CData(std::string str = "null", int x = 0, int y = 0) : m_name(str), m_x(x), m_y(y) {}
// Helper functions
const std::string& GetName() const { return this->m_name; }
const int& GetX() const { return this->m_x; }
const int& GetY() const { return this->m_y; }
};
When you build your project, each .cpp file gets compiled separately into different object files. The once in #pragma once only applies to the compilation of a single .cpp file, not for the project as a whole. Thus if a .cpp file includes header A and header B, and header B also includes header A, then the second include of header A will be skipped.
However, if you have another .cpp file that includes A, A will be included in that object file again -- because #pragma once only works when compiling a single .cpp file.
An #include statement literally takes the content of the included file and "pastes" it into the file that included it. You can try this by looking at the output of the C preprocessor tool (cpp in the gcc toolchain). If you are using the gcc toolchain, you can try something like this to see the file after its includes have been applied:
cpp file.cpp -o file_with_includes.cpp
If you have a function in your header, like Assert in your example, the function gets replicated into each .cpp file you include it in.
If you have A.cpp and B.cpp, that both include your Constants.h file, each object file (.o or .obj depending on your environment) will include a copy of your Assert function. When the linker combines the object files to create a binary, both object files will declare that they provide the definition for Assert, and the linker will complain, because it doesn't know which one to use.
The solution here is either to inline your Assert function, like this:
inline void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
or to provide its body in its own .cpp file, leaving only the function prototype in the header.
Constants.h:
void Assert(bool val, string s);
Constants.cpp:
void Assert(bool val, string s)
{
if (!val)
{
cout << "Assertion Failed!!: " << s << endl;
exit(-1);
}
}
Mind you, the Standard Library also offers assert(), which works nicely too. (see https://en.cppreference.com/w/cpp/error/assert).
#include <cassert>
...
assert(is_my_condition_true());
assert(my_variable > 23);
// etc..
Just keep in mind that the assert declared in cassert only works when compiling for Debug, and gets compiled out when building for Release (to speed up execution), so don't put any code in assert that has side effects.
#include <cassert>
...
// Don't call functions with side effects.
// Thus function decreases a "count" and returns the new value
// In Release builds, this line will disappear and the decrement
// won't occur.
assert(myclass.decrement_count() > 0);
I'm new to classes and object-oriented programming. Our instructor is having us create a program that must have a .cpp file, a main .cpp file, and a .hpp file.
Here are each of the files:
First, the odometer.hpp file:
class Odometer
{
int miles;
float gallons, mpg;
public:
//Constructors
Odometer(); //Default
Odometer(float g, int m);
//Mutator Functions
void Set_miles(int m);
void Set_gallons(float g);
//Functions
void Add_trip(int m, float g);
int Check_mileage(float g);
void Print_info();
//Accessor Functions
float Get_mpg();
float Get_gallons();
int Get_miles();
};
Next, the odometer.cpp file:
#include "odometer.hpp"
#include <iostream>
//Constructors
Odometer::Odometer()
{
miles = 0;
gallons = 0.0;
mpg = 0.0;
}
Odometer::Odometer(float g, int m)
{
miles = m;
gallons = g;
mpg = m / g;
}
//Mutator functions
void Odometer::Set_miles(int m)
{
miles = m;
}
void Odometer::Set_gallons(float g)
{
gallons = float(g);
}
//Accessor functions
float Odometer::Get_mpg()
{
return mpg;
}
float Odometer::Get_gallons()
{
return gallons;
}
int Odometer::Get_miles()
{
return miles;
}
//Other functions
//Takes # of gallons & # of miles and adds it to previous values, calculating
//new miles/gallon for whole trip
void Odometer::Add_trip(int m, float g)
{
miles += m;
gallons += g;
mpg = miles / gallons;
}
int Odometer::Check_mileage(float g)
{
int newMiles = g * mpg;
return newMiles;
}
void Odometer::Print_info()
{
std::cout << "Miles: " << miles << " Gallons: " << gallons <<
" Miles/Gallon: " << mpg;
}
And finally, the odometer_main.cpp file (so far, it's incomplete):
#include <iostream>
#include "odometer.cpp"
using namespace std;
int main(void)
{
//Odometer odDefault; //Odometer object set to defaults
Odometer od(10, 100); //Odometer object with values set
return 0;
}
These are the errors I'm getting when I try compiling all the files:
/tmp/ccArjYHP.o: In function 'Odometer::Odometer()':
odometer_main.cpp:(.text+0x0): multiple definition of 'Odometer::Odometer()'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0x0): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Odometer()':
odometer_main.cpp:(.text+0x0): multiple definition of 'Odometer::Odometer()'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0x0): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Odometer(float, int)':
odometer_main.cpp:(.text+0x30): multiple definition of 'Odometer::Odometer(float, int)'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0x30): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Odometer(float, int)':
odometer_main.cpp:(.text+0x30): multiple definition of 'Odometer::Odometer(float, int)'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0x30): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Set_miles(int)':
odometer_main.cpp:(.text+0x72): multiple definition of 'Odometer::Set_miles(int)'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0x72): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Set_gallons(float)':
odometer_main.cpp:(.text+0x8a): multiple definition of 'Odometer::Set_gallons(float)'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0x8a): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Get_mpg()':
odometer_main.cpp:(.text+0xa8): multiple definition of 'Odometer::Get_mpg()'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0xa8): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Get_gallons()':
odometer_main.cpp:(.text+0xbc): multiple definition of 'Odometer::Get_gallons()'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0xbc): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Get_miles()':
odometer_main.cpp:(.text+0xd0): multiple definition of 'Odometer::Get_miles()'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0xd0): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Add_trip(int, float)':
odometer_main.cpp:(.text+0xe0): multiple definition of 'Odometer::Add_trip(int, float)'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0xe0): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Check_mileage(float)':
odometer_main.cpp:(.text+0x140): multiple definition of 'Odometer::Check_mileage(float)'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0x140): first defined here
/tmp/ccArjYHP.o: In function 'Odometer::Print_info()':
odometer_main.cpp:(.text+0x168): multiple definition of 'Odometer::Print_info()'
/tmp/cc1W9Ght.o:odometer.cpp:(.text+0x168): first defined here
collect2: error: ld returned 1 exit status
makefile:2: recipe for target 'odometer' failed
make: *** [odometer] Error 1
In short, replace #include "odometer.cpp" with #include "odometer.hpp". Now for the why.
Your program consists of source files like main.cpp and odometer.cpp. These files contain definitions for functions, variables, or classes in your project. Your compiler compiles each source file (.cpp) separately into object files (.o), and then your linker links these object files together to form your program.
However, although your source files are compiled separately, they will need to interact with each other. main.cpp will want to create Odometer objects and access Odometer member functions and so on. So we need a way to tell main.cpp what an Odometer is. The easiest way to do that is to define Odometer in a header file, and #include that header in main.cpp.
#include is a preprocessor directive that inserts the contents of another file into the current file. The preprocessor runs before your code is actually compiled. The idea is that you have some declarations in a file, which we call a header file, and multiple source files that need access to those declarations. So each source file will #include the header.
Note though that main.cpp doesn't need access to the definitions of Odometer's member functions, it just needs to know what those functions are and how to call them. That information is in the class definition in odometer.hpp, not in odometer.cpp. It would be an error to #include "odometer.cpp", because then we would have functions that are defined in two different places, and the linker will complain.
So in general you put your class definition in a header file (.hpp), put the class implementation in a source file (.cpp), and #include the header file in any other source file that needs access to that class. If you structure your programs correctly in this way, you should never need to #include a .cpp file into another .cpp file.
The are multiple problems here:
odometer.hpp
Odometer(float g, int m): This is not defined in odometer.cpp
Odometer() : This default constructor should also be defined in odometer.cpp
Odometer has three member variables but only two are taken as input, it is unclear how the third mpg is initialized
There are no include guards in your header file
#ifdef ODO_H
#define ODO_H
class Odometer{
// your class declaration
};
#endif
odometer.cpp
#include "odometer.hpp"
#include <iostream> - since you are using std::cout
Provide definitions for various Odometer constructors.
main.cpp
#include "odometer.hpp" - since you are using Odometer class here
Solving these issues should help you compile your code.
If you are including your odometer.cpp into your odometer_main.cpp, you can't also compile separately your odometer.cpp and link it with your odometer_main.cpp. In that case, yeah, you will get duplicate symbols. The typical way, though, is to only include the .hpp file into your main, and all else should compile and link fine.
It is important to used file exclusion directives to avoid multiple inclusion.
#ifndef ODOMETER_H
#define ODOMETER_H
#include "odometer.h"
#endif
Have a look at this question:
Why are #ifndef and #define used in c++ header files
Also as the guys commented, you should include the h file
I have a conceptual doubt which i'll try to put across using an example:
main.cpp
#include "array_list.cpp"
int main()
{
array_list list1;
return 0;
}
Scenario1:
array_list.cpp->
class array_list
{
private:
int list[10];
public:
array_list () {};
~array_list () {};
void set_element (int,int);
};
void array_list::set_element (int i,int a) {
list[i] = a;
}
Error:
main.obj : error LNK2005: "public: void __thiscall array_list::set_element(int,int)" (?set_element#array_list##QAEXHH#Z) already defined in array_list.obj
1>C:\Users\vrastog\Documents\Visual Studio 2012\Projects\C++ learning\Debug\list using arrays.exe : fatal error LNK1169: one or more multiply defined symbols found
Scenario 2:
array_list.cpp->
class array_list
{
private:
int list[10];
public:
array_list () {};
~array_list () {};
void set_element (int i,int a) {
list[i] = a;
}
};
Error: No error!!
Question: I understand the reason for error. The same method has been defined twice, once in main.obj and second in array_list.obj and hence, it should be an error.
My question is why does the second scenario work? Here also, since we have includes array_list.cpp in the main file, 'set_element' should have been defined twice here as well. What am I missing here?
Please don't include .cpp files.
In the first example, the function is defined out of class, you need to add inline, otherwise it's a multiple definition.
In the second example, the function is defined in the class definition, so it's an implicit inline function (it's like the compiler added the inline for you), that's why it's not causing multiple definitions.
In-class definition makes a method inline, and therefore it does not cause a multiple definition error in the object file.
An inline method should be implemented in every translation unit it is used in, so the inline method compiles into both object files.
C++ Standard Draft (n3797) 3.2.4: An inline function shall be defined in every translation unit in which it is odr-used.
Also 3.2.6 requires that these function should be exactly the same.
g++ implements this using weak symbols: inline functions are special exported functions that do not cause multiple definition error when linking.
Use a tool like nm under Linux and see for yourself. It emits a weak symbol into the object file:
$ nm arraylist.o
00000000 W _ZN10array_list11set_elementEii
(... ctors, dtors ...)
00000000 T main
Also, if you do not use the function, or the compiler inlines all occurrences, it may get optimized out.
I'm writing a simple game engine, and I have the EntityComponent.h file:
#ifndef Psycho2D_Core_EntityComponent_
#define Psycho2D_Core_EntityComponent_
#include <string>
namespace psycho2d{
class EntityComponent{
private:
std::string m_name;
public:
EntityComponent(const std::string &name);
virtual ~EntityComponent();
const std::string& getName() const;
virtual void initialize() = 0;
virtual void loadProperties() = 0;
virtual void update() = 0;
virtual void destroy() = 0;
};
}
#endif
And the relative EntityComponent.cpp file:
#include "EntityComponent.h"
#include <string>
psycho2d::EntityComponent::EntityComponent(const std::string &name){
this->m_name = name;
}
psycho2d::EntityComponent::~EntityComponent(){}
inline const std::string& psycho2d::EntityComponent::getName() const{
return this->m_name;
}
These two file are part of a framework (I'm working on a Mac). They compile well.
The problem is when I write an executable that use the library.
I have created a sub-class of EntityComponent, and it compiles. But, if I call the getName() function, the linker tell me:
"psycho2d::EntityComponent::getName() const", referenced from:
_main in main.o
Symbol(s) not found
Collect2: ld returned 1 exit status
What I can do?
Thanks.
Put the code for the inline function in the header file, if you want to reference it from multiple .cpp files.
Reference here.
An external linkage inline function must defined (as effectively the same) in every translation unit where it's used.
So either remove the inline from the definition, or place the definition in the header file.
Cheers & hth.,
Your (slightly modified to include a subclass to text) code compiles fine on my machine (A Mac, too. GCC 4.2.1)
Try removing all .o-files and compile with a clean directory. If that fails too, I'd try to remove the inline-definition.
Try removing the inline qualifier from your implementation.