7

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.

thko
  • 113
  • 1
  • 1
  • 8
  • 1
    Also be sure to add "-I" to your compile line. Perhaps even "-I.", if your .h files are in the same directory. – paulsm4 Jan 05 '12 at 00:00
  • 3
    It works for me. I just copied your `main.cpp`, `Complex.h`, and `Complex.cpp`, and ran `g++ main.cpp Complex.cpp`. It created `a.out` just fine. – ruakh Jan 05 '12 at 00:01
  • 1
    Works for me too. @paulsm4: shouldn't `.` be in the default include path? (note that he's doing `#include "..."`, not `#include <...>`) – Ricardo Cárdenes Jan 05 '12 at 00:03
  • 3
    Paste the *exact* errors you get when you do `g++ main.cpp Complex.cpp`. – David Schwartz Jan 05 '12 at 00:04
  • 1
    Did you post the actual code? I can't see anything wrong with this code and g++ compiles the code fine for me. Although I'm using MacOS I doubt that I would have a different experience if I used Linux. – Dietmar Kühl Jan 05 '12 at 00:04
  • 1
    Works on Linux too. I don't think there's a reason why the data in the question should fail as it is. – Ricardo Cárdenes Jan 05 '12 at 00:17
  • This is the same code I was using before but with some functions and operators trimmed out. Using this code I get different errors (inserted into the OP). This is confusing me a lot and none of the webpages I've visited have provided any insight. – thko Jan 05 '12 at 00:54
  • 1
    Rename your `Complex.*` files. On the Windows side, you may be conflicting with some other `complex.h` with different case. I think there's a legacy C++ `` somewhere (now just ``) which defined the `std::complex<>` template. – Mike DeSimone Jan 05 '12 at 01:03
  • 1
    @MikeDeSimone: I bet you're right. If I try this on a Windows machine using GCC 4.5.2, and change `#include "Complex.h"` to `#include `, I get the OP's exact error-messages (verbatim). Admittedly, I don't get any errors when I use the code (s)he actually posted (with quotes rather than angle-brackets), but IMO it's still the best bet. – ruakh Jan 05 '12 at 02:37
  • That doesn't explain why he claims to get the same errors with "g++ on Ubuntu". – Carl Norum Jan 05 '12 at 03:16
  • Ubuntu may have a (C?) library installed that has a "complex.h" declaring a `complex` type of some form (with a lowercase name so the capitalized name is undefined). – Mike DeSimone Jan 05 '12 at 04:57

2 Answers2

7

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
Carl Norum
  • 210,715
  • 34
  • 410
  • 462
  • In the question, it already says "I've tried `g++ main.cpp Complex.cpp"` – Aaron McDaid Jan 05 '12 at 00:12
  • @AaronMcDaid, but he obviously hasn't, since that will work. I suppose he could be oversimplifying his example, too, but that's not going to help him get the right answer either. – Carl Norum Jan 05 '12 at 00:12
  • I agree. I'd already upvoted your answer as it seems obviously right :-) I suppose we are waiting on the details of the exact error message. – Aaron McDaid Jan 05 '12 at 00:16
  • Probably want a `-o` flag on the link step unless you're fond of your programs being named something like `a.out`. – Mike DeSimone Jan 05 '12 at 00:59
  • @MikeDeSimone, I was just looking for the bare minimum flag set to avoid confusing the issue. The OP didn't appear to be using any `-o` flags. – Carl Norum Jan 05 '12 at 03:15
1

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.
Dietmar Kühl
  • 145,940
  • 13
  • 211
  • 371