tags:

views:

145

answers:

4

I keep running into problems the larger my program gets. For instance, I get the following error:

In file included from WidgetText.h:8,
                 from LCDText.h:17,
                 from WidgetText.cpp:13:
Generic.h:21: error: expected class-name before ',' token

Here are those lines:

#include "Generic.h" // WidgetText.h:8

#include "WidgetText.h" // LCDText.h:17

#include "LCDText.h" // WidgetText.cpp:13

class Generic: public virtual LCDText, public CFG, public virtual Evaluator { // Generic.h:21

Here are the contents of the various header files:

//Generic.h
#include "CFG.h"
#include "Evaluator.h"
#include "LCDText.h"
#include "Widget.h"

//WidgetText.h
#include "Generic.h"
#include "Property.h"
#include "Widget.h"

//LCDText.h
class Generic;
#include "LCDBase.h"
#include "WidgetText.h"

This isn't providing much; I know. I'm not sure what else to include. Each header defines a class named after its header, so LCDText.h has a class named LCDText.

The one line declaring class 'Generic' in LCDText.h had to be placed there due to an earlier problem similar to this one. I'm assuming this current issue has a similar solution, but I've failed to find it thus far.

+7  A: 

You have a circular dependency: Generic.h includes LCDText.h which includes WidgetText.h which includes Generic.h; the error stems from this basic problem. If you can rework your headers to eliminate this cycle, chances are the error will either resolve itself in the refactoring or the problem will become much more obvious than it is now.

fbrereto
This is also called a "cyclic dependency" (in case you want to search for more about this problem).
ChrisW
+3  A: 

From the code presented here, it seem that you are include the header filed multiple times. To prevent problems you need conditional guards in your header files.

David Harris
+2  A: 

Part of the solution is to add some forward declarations to get rid of these compiler errors (just like you did with your class Generic line). Google will turn up lots of suggestions on how exactly to do this.

Using forward declarations will let you eliminate the cyclic / circular #includes described in this answer.

A forward declaration lets you include references to and pointers to the forward-declared class, and it lets you pass the forward-declared class as a parameter, but it does not let you derive from or include an instance member of the forward-declared class. So your Generic class needs a way to #include (and not just forward-declare) the header files for LCDText, CFG, and Evaluator. If it can't do that because LCDText, CFG, or Evaluator need to #include (and not just forward-declare) Generic, then you need to rearrange your hierarchy to fix this (for example, by making a member variable a pointer or reference to a class instead of making it an instance of a class).

However, using multiple inheritance like this (and especially using the diamond inheritance implied by two virtual inheritances) is a definite code smell. It suggests that you should be designing your class hierarchy differently. For example, maybe you need to be favoring composition over inheritance. That would make cleaning up your forward declarations and cyclic dependencies a lot easier.

Edit: You mentioned that you've been running into this problem more as your code base gets larger. I'm told that John Lakos's Large-Scale C++ Software Design is a good reference for managing issues such as header file dependencies in large projects, although it may be overkill for where your project is right now.

Josh Kelley
When I started running into these problems I limited the inheritance some. Your comments helped me figure it out. I had Generic.h, which isn't inherited by much, included everywhere. Forward declaring Generic instead fixed the problem. I'll have to go through and see what else I can change.
Scott
I'll second the recommendation of John Lako's book. Anyone designing sizeable systems in C++ should read it.
Stephen C. Steel
+2  A: 

Others have already pointed out the circular dependency but if you're still unsure of how to fix it then it looks for all the world as if you need to forward declare Generic in WidgetText.h i.e. line 8 becomes

class Generic;

If you've already tried that, and it sounds as if you have, then you need to examine how you are using Generic in WidgetText.h and see if you can eliminate places where you are relying on having the full definition eg. change an aggregated Generic to a Generic* or move an inline member that accesses a Generic method into an out-of-line definition in a source file.

Troubadour