thko
thko

Reputation: 123

File inclusion errors (C++): undefined reference to ______

Whenever I compile something that #includes a user-defined class, I get these compilation errors that always look like: main.cpp: undefined reference to Complex::Complex(double, double)

I've reduced the problem to a set of three extremely bare files: main.cpp, and for example, Complex.h and Complex.cpp. I still get undefined reference errors. I'm developing in Code::Blocks on Windows but I get the same thing using g++ in Ubuntu. Why does this happen? I've tried building Complex.cpp before main.cpp in Code::Blocks, and I've tried g++ main.cpp Complex.cpp as much as I've tried just g++ main.cpp. Same errors every time.

/*======== main.cpp ========*/
#include "Complex.h"

int main()
{
    Complex A(1.0, 1.0);
    return 0;
}

/*======== Complex.h ========*/
#ifndef _COMPLEX_H
#define _COMPLEX_H

class Complex
{
    public:
    double x, y;
    Complex(double real, double imag);
};

#endif

/*======== Complex.cpp ========*/
#include "Complex.h"

Complex::Complex(double real, double imag)
{
    x = real;
    y = imag;
}

ed: now I get different errors so I must be doing something completely wrong. Using the same code as above, I get:

main.cpp: in function 'int main()':
main.cpp:5:5: error: 'Complex' was not declared in this scope
main.cpp:5:13: error: expected ';' before 'A'

This is bizarre. Everything worked earlier when I had the class in a .cpp file, but that's "bad practice" so I moved my class definitions into .h files and kept the implementation in .cpp files, and now nothing works.

Upvotes: 7

Views: 17955

Answers (2)

Dietmar Kühl
Dietmar Kühl

Reputation: 154015

While we are left in the dark whether this is the actual code (probably not as it works for several others), let's comment on the code itself a bit... (this won't have any effect on the linker error)

  1. Names starting with an underscore followed by a capital letter, e.g. _COMPLEX_H, are reserved for the implementation of the C++ compiler and the C++ standard library. Don't use them.
  2. Member variables are best made private. There is rarely any need to make actual data member public (sometimes it is reasonable to make non-function members public, e.g. an event class where users can subscribe callbacks, but these typically behave like functions although they are technically objects).
  3. Initialization is best done in the member initializer list. That is, the constructor would look something like this:

    Complex::Complex(double real, double image): x(real), y(imag) { }

Finally, to venture a few guesses what is going wrong with the actual code to cause the linking problem:

  1. The constructor is defined to be inline. Obviously, this won't work unless the definition is visible where the constructor is used.
  2. The declaration of Complex somehow made it into an unnamed namespace and thus the definition happens to define a different class than the one seen by main.cpp.

Upvotes: 1

Carl Norum
Carl Norum

Reputation: 225142

That's not a compilation error, it's a link error. You need to make sure to link all of your objects together. You can do that in a couple ways:

g++ main.cpp Complex.cpp

Should work fine (and does here when I tried with your example). You can also do it in steps:

g++ -c main.cpp
g++ -c Complex.cpp
g++ main.o Complex.o

Upvotes: 7

Related Questions