Well, use forward declarations. As you said, there are millions of explanations out there, and now there are millions and one:
ErrorToken.h:
#ifndef H_ERROR_TOKEN
#define H_ERROR_TOKEN
#include "Token.h"
class EndToken;
class ErrorToken : public Token
{
public:
EndToken makeEndToken();
};
#endif
EndToken.h:
#ifndef H_END_TOKEN
#define H_END_TOKEN
#include "Token.h"
class ErrorToken;
class EndToken : public Token
{
public:
ErrorToken makeErrorToken();
};
#endif
In each implementation file, you can now happily include both headers:
#include "ErrorToken.h"
#include "EndToken.h"
ErrorToken EndToken::makeErrorToken()
{
return ErrorToken(); // example
}
EndToken ErrorToken::makeEndToken()
{
return EndToken();
}
As @James Kanze pointed out, you might be confused about how C++ works. The following code may be more in line with the kind of behaviour you expect from Java, and makes more sense in a polymorphic design way:
class Token { virtual ~Token() {} };
class ErrorToken : public Token
{
std::unique_ptr<Token> makeEndToken();
};
class EndToken : public Token
{
std::unique_ptr<Token> makeErrorToken();
};
std::unique_ptr<Token> EndToken::makeErrorToken()
{
return { new ErrorToken; }
}
std::unique_ptr<Token> ErrorToken::makeEndToken()
{
return { new EndToken; }
}
Since you're only handling objects via base pointers, the headers don't need to know anything about other derived classes. (I leave it to you to subdivide the code into files; each block goes into a separate file.)