1

I am programming on linux using g++ and I often encounter the problem that I need to use a class or data type in a header file which I define later, either at a later point in the header or in another header file.

For instance look at this header file:

class example
{
    mydatatype blabla;
};

struct mydatatype
{
   int blablainteger;
   char blablachar;
};

This will give error because mydatatype is used before its defined so usually I change it like this:

struct mydatatype; // <-- class prototype
class example
{
    mydatatype *blabla; // <-- now a pointer to the data type
    // I will allocate the data during runtime with the new operator
};

struct mydatatype
{
   int blablainteger;
   char blablachar;
};

Now it works. I could often just put the definition above, or include the header which is needed, but I don't want to include headers in a header or juggle with the definition order, it always gets messy.

The solution I showed usually works, but now I have encountered a new phenomenon. This time the datatype is not a class but a typedef, I cant use prototypes for a typedef and I don't want to use the actual datatype which the typedef incorporates.. it's messy too.
Is there any solution to this?

SteveL
  • 1,811
  • 1
  • 13
  • 23
alfalfa
  • 147
  • 1
  • 8
  • 4
    Including headers within headers is normal practice. Just make sure to use guards to avoid the header being included twice, and make sure you don't have recursive includes. – Vaughn Cato Jan 12 '13 at 16:31
  • @VaughnCato Why is recursive inclusion a problem? That's so nice about the guards! Or am I not understanding you properly? – antonijn Jan 12 '13 at 16:46
  • @AntonieBlom: If your includes are recursive, then you can end up having things defined in an unexpected order. Plus, it indicates a circular dependency which isn't good in general. – Vaughn Cato Jan 12 '13 at 16:50
  • 1
    If your headers don't include their dependencies then you are creating the exact situation that you are trying to avoid. You place the burden of including dependencies of your header on the users of the header and they must include them in specific order. Self-contained headers are much easier to work with and don't have any of these problems. Just make sure to use include guards (or `#pragma once`). – sdkljhdf hda Jan 12 '13 at 16:50

3 Answers3

0

Place each class/type in it's own header file, and then include the relevant header file in other headers where you need it. Use an inclusion guard in each header e.g.:

// SomeHeaderFile.h
#ifndef SOME_HEADER_FILE_H
#define SOME_HEADER_FILE_H
// code
#endif

I disagree that this is messy - it allows you have an organised structure to you project, it allows each class to operate independently of others and without worrying about order, and it's a good idea to place each class in it's own file anyway.

JBentley
  • 6,099
  • 5
  • 37
  • 72
0

Firstly, the solution you've thought of (prototype and pointer), is unneeded, and slower than just implementing it without the pointer.

The "proper" solution for this, would be creating seperate headers for each type, and then include them in your other header. That way it will always be defined! You can even make them so that they include eachother.

However, if you've ever opened a .h file provided by g++, you've most likely seen this at the start of the header:

#ifndef SOMETHING_H
#define SOMETHING_H

// Code

#endif /* SOMETHING_H */

This is to solve the issue of types redefining themselves.

If they weren't there, and you included the header file multiple times, the types would be redefined, and an error would be thrown. This makes it so that the types are always present, but never included twice.

I hope that helps!

antonijn
  • 5,702
  • 2
  • 26
  • 33
  • 1
    `__something_h__` isn't the best of choices: http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier – chris Jan 12 '13 at 16:40
  • @chris I thought I'd use that beccause g++ sometimes uses that (or at least in some of the headers that I've seen). To be honest, I don't like that either, and now that I see that it goes against the standards, I've changed it. – antonijn Jan 12 '13 at 16:43
  • @JonBentley - names that contain two underscores and names that begin with an underscore followed by a capital letter are reserved to the implementation. – Pete Becker Jan 12 '13 at 18:23
  • It's not specific to the preprocessor. The language reserves them to the implementation. [global.names]/1: "Certain sets of names and function signatures are always reserved to the implementation: — Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase letter (2.12) is reserved to the implementation for any use." – Pete Becker Jan 12 '13 at 18:32
0

You could just define the class inside the other class like

template<class T>
class vertex {
private:
    class edge {
    public:
        vertex<T> *to;
        double weight;
        edge() {
            weight = INFINITY;
            to = NULL;
        };
    } *paths;
    T data;
    unsigned nof_paths;
public:

    vertex(T val) {
        data = val;
        paths = NULL;
        nof_paths = 0;
    }
    void addPathTo(vertex<T>*&);

    edge* getAllPaths() {
        return paths;
    };
};

Obviously this works for small classes... if your class is ENORMOUS you'll be better using separate header files like the other guys said.