Dooms101
Dooms101

Reputation: 492

Constants and Classes Declarations Across Multiple Source Files in C++

I am sure this problem is asked a lot but I can't seem to find anything relevant. I have multiple source files in a C++ project. In typical fashion, there are multiple header files with class and function declarations and associated source files with their definitions. The problem is that when I try to use one of my classes defined in another file as a member for a class in a different file, I get compile errors even when uses the #include directive. What fixes the problem is by prototyping (is that the right word?) the class first before declaring it a member. So if ClassA is in one file and ClassB is in another and I want to use a ClassA member in ClassB I must write:


// ClassA.h
class ClassA {
    public: ClassA (void); };
// ClassB.h class ClassA; // prototype class ClassB { public: ClassA* ca; };

Is this normal? It doesn't matter if I use pointers or instances, I still must prototype them. I have found that I also must prototype structs and enums if they are in separate files. I can't seem to use constants declared using #define, or const across multiple files I get errors that they are undefined so I am not sure how to give them more than file scope. The same goes for typedefs. I am sure there is some easy fix to this that I am not remembering... any help is appreciated!

Upvotes: 0

Views: 932

Answers (3)

To expand on Konrad's answer:

Yes, that's fine and dandy when you don't have to deal with circular references. If you do have to worry about circular inheritance, the diamond problem, or anything of the sort, here's a solution I found in someone else's question:

// ClassA.h
class ClassB;

class ClassA {
    public:
        ClassB* cb;
};


// ClassA.cpp
#include "ClassA.h"
#include "ClassB.h"
// code


// ClassB.h
#include "ClassA.h"

class ClassB {
    public:
        ClassA* ca;
};


// ClassB.cpp
#include "ClassB.h"
// code

As long as ClassA only tries to access members of ClassB inside member functions, and the member functions are all in the source file, you can just use a class declaration in the header, and leave the #include for the source file, where ClassA.h's include guard will solve the problem for you.

Upvotes: 0

Keynslug
Keynslug

Reputation: 2766

Yes it is obvious way.

This approach is most suitable when you're trying to avoid mutual dependencies among headers. If you're sure that no mutual dependency appears between two headers it is normal that you #include one in another.

Upvotes: 0

Konrad Rudolph
Konrad Rudolph

Reputation: 545638

The word you’re looking for is “declare”, not “prototype”.

In any case, that’s normal. Usually you’d just include the relevant header files:

// ClassB.h

#include "ClassA.h"

class ClassB {
public: ClassA* ca; };

This will cause problems with circular references, though (but in all other cases it’s fine).

Another thing: Don’t forget your include guards, to protect against multiple inclusion of a file. That is, always write header files in the following way:

#ifndef UNIQUE_IDENTIFIER_HERE
#define UNIQUE_IDENTIFIER_HERE

// Rest of header file here.

#endif // ndef UNIQUE_IDENTIFIER_HERE

The UNIQUE_IDENTIFIER_HERE is usually an all-uppercase variant of the header file name, e.g. ‹PROJECTNAME›_‹PATH_TO_HEADER›_‹HEADERNAME›_H. For example, I’m currently working in a project (called “SeqAn”) that has a header file in the path parallel/taskdata.h. The unique identifier I use is thus SEQAN_PARALLEL_TASKDATA_H.

Upvotes: 2

Related Questions