3

This is a weird problem that I was wondering if anyone else had seen. We're writing cross-platform C++ code for Mac and PC, and this only occurs on Mac.

Say I have a class, whose .h file looks like this.

class X {
public:
    int _myValue;
    void myFunction();
}

And I have another class, whose .h file looks like this:

#include "X.h"
class Y {
private:
     X _myObj;
}

This won't compile. We get an error indicating X is undefined. The solution is to add a forward declaration for X in the Y.h file, such as: class X;

We've been doing this for a while, but now we're getting into situations where it's not working so well. For example, if we have a .h file that has a templates method defined in the .h file, and that method references a method in another class, the compiler doesn't know anything about it. Likewise, if we reference an enum that's defined in a class that was included, the compiler doesn't recognize it (the workaround for this problem was to put the enum in a separate .h file, and it picked it up just fine).

It's almost as if while compiling the .cpp file the compiler isn't pulling in the data from the included .h file.

I was just wondering if anyone had seen anything like this, or had possible avenues of investigation.

Much thanks...

crashmstr
  • 28,043
  • 9
  • 61
  • 79
  • `#include "X.h"` or `'include "x.h"`? Are you getting any warnings such as "failed to find 'X.h'"? – CB Bailey Mar 14 '12 at 17:07
  • 1
    Can you post an actual minimal example that exhibits the problem you're having (including the cpp file)? When I try to compile your header files, the compiler rightly complains that your class declarations are missing semicolons at the end. When I fix this, the code compiles fine with gcc 4.2 under Mac OS. (My suspicion is that your actual header files contain include guards or `#pragma once` and that your problem is related to this.) – Martin B Mar 14 '12 at 17:10
  • You might want to look to see if you have an old copy of the X.h header sitting around which is being picked up by the compiler instead of the latest header. – Nathan S. Mar 14 '12 at 18:32
  • Where are the headers stored? Check you Project Settings Build Tab. Scroll down to the Search Paths section and make sure your headers can be found. Also read the help for Always Search User Paths, although that's probably off topic. – Tod Mar 14 '12 at 19:09
  • It's important to remember that the Apple default file system doesn't distinguish case. So "X.h" and "x.h" are the same file name. – Charlie Martin Mar 14 '12 at 19:17
  • "The solution is to add a forward declaration for X in the Y.h file, such as: class X;" That's not a solution. It's just something you tried which happened to make things look like they were working. First you need to really figure out what the problem is. Start by trying to create a minimal example that exhibits the issue. – bames53 Mar 14 '12 at 19:19

3 Answers3

1

There is a common system header file X.h which is part of the X11 windowing toolkit. I recommend changing the name of your header file so that it doesn't clash with any system headers.

You could try to alter your compiler switches to force it to consider the directory containing your header file before your system include directories but this is probably more effort and more fragile.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
0

For your first issue (classes), the correct answer is to use a forward declaration. You should avoid including project include files in other project include files. This can create include loops (which is most likely your issue if I had to guess). It also creates excessive build churn when you modify a header.

For your other issues (enums, templates), this is usually due to include cycles. Breaking those cycles by avoiding includes whenever possible is your best bet.

For more discussion on this issue and best practices, see Header file best practices for typedefs.

Community
  • 1
  • 1
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 1
    A forward declaration (only) in Y.h is not appropriate as X appears as a value member of Y. A full definition of X is required. – CB Bailey Mar 14 '12 at 19:18
  • You're absolutely correct in this case. You should avoid the include *when possible*, but as you note, it's not possible in this case. – Rob Napier Mar 14 '12 at 19:27
0

I'm just a touch surprised that no one else has mentioned the canonical scheme for include files, eg,

foo.h:

#ifndef FOO_H
#define FOO_H
// body of the include file
#endif

I suspect that in this specific case, the clash of "x.h" and "X.h" may be the issue you're seeing, but if you don't guard the include files like this it will bite you eventually.

With that guard, you can include "x.h" anywhere you need it.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263