Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Member classes versus #includes

I've recently discovered that it is bad form to have #includes in your header files because anyone who uses your code gets all those extra includes they won't necessarily want.

However, for classes that have member variables defined as a type of another class, what's the alternative?

For example, I was doing things the following way for the longest time:

/* Header file for class myGrades */
#include <vector>           //bad
#include "classResult.h"    //bad

class myGrades
{
    vector<classResult> grades;
    int average;
    int bestScore;
}

(Please excuse the fact that this is a highly artificial example)

So, if I want to get rid of the #include lines, is there any way I can keep the vector or do I have to approach programming my code in an entirely different way?

like image 535
ShallowThoughts Avatar asked Feb 25 '23 06:02

ShallowThoughts


2 Answers

If your class directly includes a data member of a given type (and not, by the way, a pointer to that type or a reference to that type), then you must have the class declaration available so that the compiler knows how many bytes an instance of your object takes up. This usually means that you have to #include the header files.

However, there are techniques known as compiler firewalls that can let you structure classes in a way that gives the class access to objects of the appropriate type without directly including them. One of these is the pImpl idiom, in which your class implementation looks like this:

class MyClass {
public:
    /* ... */

private:
    struct Impl;
    Impl* pImpl;
};

Here, you forward-declare a struct Impl containing your class's implementation, then store a pointer to the Impl struct in the class. Since having a pointer in your class doesn't require the size of the object being pointed at to be known, this is perfectly fine. Then, in the .cpp file, you can define the Impl struct:

struct MyClass::Impl {
    /* ... */
};

and you can implement all of the class's member functions by just following the pImpl pointer to the actual fields. This has the drawback that all field accesses require a pointer indirection, but the ability to change the class implementation so quickly does make this useful.

Another option along the same lines is to make the class an abstract base class, then to provide a static factor function that returns an object subclassing your base class that actually contains the implementation. For example:

class MyClass {
public:
    virtual ~MyClass(); /* Need virtual dtors in polymorphic classes! */

    virtual void doSomething() = 0;
    /* ... etc. ... */

    static MyClass* New(/* ... args ... */);
};

Then, in the .cpp file you can define a concrete subclass of MyClass that actually does all the work:

class ActualClass: public MyClass {
public:
     void doSomething();
     /* ... etc. ... */

private:
     /* ... data members ... */
}

and finally, implement New to create a new instance of the implementation class:

MyClass* MyClass::New(/* ... args ... */) {
    return new ActualClass(/* ... args ... */);
}

Hope this helps!

like image 170
templatetypedef Avatar answered Mar 08 '23 18:03

templatetypedef


There is absolutely nothing wrong with including other headers in your header.

You need to be sure that your header includes all of the headers that it depends upon and you should avoid including extraneous, unneeded headers.

like image 24
James McNellis Avatar answered Mar 08 '23 17:03

James McNellis