views:

852

answers:

10

I usually, almost without thinking anymore, use forward declarations so that I won't have to include headers. Something along this example:

//-----------------------
// foo.h
//-----------------------
class foo
{
   foo();
   ~foo();
};


//-----------------------
// bar.h
//-----------------------

class foo; // forward declaration

class bar
{
   bar();
   ~bar();

   foo* foo_pointer;
};

Some developers like to use this method to avoid problems with inclusion circles. I rather use it to minimize the overhead in extensive inclusion hierarchies, an important part of physical design (for larger projects in particular).

However, in some cases I really like to declare members as normal objects instead of pointers to benefit from the automatic construction/destruction mechanism. This leads to the problem that forward declarations can't be used anymore, since the compiler needs the class definition in such case, eg:

//-----------------------
// foo.h
//-----------------------
class foo
{
   foo();
   ~foo();
};


//-----------------------
// bar.h
//-----------------------

class foo;       // Not enough given the way we declare "foo_object"..
#include "foo.h" // ..instead this is required

class bar
{
   bar();
   ~bar();

   foo foo_object;
};

So, I would be happy if anyone knows an alternative language construct which can be used here so that I can declare "foo_object" as shown in the example, but without including its header.

Regards

/Robert

A: 

If you are able to use a reference, you can retain the same use syntax. However, your reference has to be initialised straight away in the constructor, so your ctor absolutely must be defined out-of-line. (You will also need to free the object in the destructor too.)

// bar.h
class foo;

class bar {
    foo& foo_;

public:
    bar();
    ~bar();
};

// bar.cc
bar::bar() : foo_(*new foo)
{
    // ...
}

bar::~bar()
{
    // ...
    delete &foo_;
}

Your mileage may vary. :-)

Chris Jester-Young
+10  A: 

You can't. The compiler needs to know the size of the object when declaring the class.

References are an alternative, although they have to be instantiated at construction time, so it's not always feasible.

Another alternative are smart pointers, but I suppose that's technically still a pointer.

It would be good to know why you don't want to use a pointer to suggest some other construct though...

Pieter
Technically, a member object isn't so different from a reference as far as instantiation-at-construction goes, so no loss there. :-)
Chris Jester-Young
A member can be default initialised, and properly (fully) set later via e.g. setters. You can't do that for a reference member.
Pieter
I want to make use of the automatic construction/destruction mechanism, so any alternative implying required tasks in constructor/destructor of host class is unfortunately not sufficient for me. Thanks.
sharkin
+5  A: 

What you want cannot be done in C++. In order to generate code for an object, your compiler needs to know how much storage its class requires. In order to know that, it must know how much storage is required for each member of the class.

If you want to create a class of type bar with a member of type foo, the compiler has to know how big a foo is. The only way it knows that is if it has the definition of foo available (via #include). Otherwise, your only option is to use a forward-declaration of foo and a pointer or reference instead of an actual foo object.

Tyler McHenry
+1  A: 

There's no way around that.

Your best bet is to limit how much is included, but you have to include the file with the class declaration. You could could split the class declarationout into a separate header which, hopefully, includes nothing else. Then yes, you have to have an #include, but you're still keeping your include hierarchy somewhat shallow. After all, including one file is cheap, it's only when the hierarchy stretches out to hundreds or thousands of files that it starts hurting... ;)

jalf
+1  A: 

Pretty much the only thing you can do is minimize the impact by using the pImpl idiom so that when you include foo.h, you're only including foo's interface.

You can't avoid including foo.h, but you can make it as cheap as possible. The habit you've developed of using foward declarations rather than #inlcudes has you well on this path.

JohnMcG
+7  A: 

Just use a smart pointer - you can even use auto_ptr in this case.

//-----------------------
// bar.h
//-----------------------

#include <memory>
class foo;       // Not enough given the way we declare "foo_object"..

class bar
{
public:
   bar();
   ~bar();

   foo &foo_object() { return *foo_ptr; }
   const foo &foo_object() const { return *foo_ptr; }

private:
   auto_ptr<foo> foo_ptr;
};

You get all the benefits of automatic memory management, without having to know anything about foo in bar.h. See Wrapping Pointer Data Members for Herb Sutter's recommendation.

If you really want default construction to happen automatically, try this:

#include <iostream>
using namespace std;

class Foo;

template <typename T>
class DefaultConstuctorPtr
{
    T *ptr;
    void operator =(const DefaultConstuctorPtr &);
    DefaultConstuctorPtr(const DefaultConstuctorPtr &);

public:
    DefaultConstuctorPtr() : ptr(new T()) {}
    ~DefaultConstuctorPtr() { delete ptr; }

    T *operator *() { return ptr; }
    const T *operator *() const { return ptr; }
};

class Bar
{
    DefaultConstuctorPtr<Foo> foo_ptr;
public:
    Bar() {} // The compiler should really need Foo() to be defined here?
};

class Foo
{
public:
    Foo () { cout << "Constructing foo"; }
};

int main()
{
    Bar bar;
}
Eclipse
doesn't this still require initialization of foo_ptr in bar's constructor?
e.James
indeed, it does. hehe
Johannes Schaub - litb
And what if you can't use auto pointers?
xan
I've heard auto pointers are being depricated, anyone else for a better answer?
MacX.dmg
roll-your-own, as several of us have described below. Even if the C++ standard removes auto_ptr, these home-grown classes will still work.
e.James
Even if they deprecate auto_ptr (which I've not heard of the standards committee doing) c++x0 will still have shared_ptr and weak_ptr.
luke
C++0x's (superior) unique_ptr is what deprecates auto_ptr
Yang
Interestingly, this actually works because of the use of templates (i.e., if you make DefaultConstructorPtr regular class with Foo replacing T everywhere, the compiler will complain about Foo not being known). I experimented a little with this and it seems that you can even move the definition of Foo below main() and it still works. Furthermore, if you then make Foo's default ctor private, the compiler complains specifically that Foo::Foo() is private. On the other hand, if you add another method and try to call it from main(), the compiler complains that Foo is undefined. Cont ...
Ari
But if you now move the definition of Foo to right above main() --- no problem again. So it seems that stuff in a template gets compiled after everything else. I wonder if this behavior is dictated by the standard, or is implementation depenent.
Ari
Templates are only half-compiled until they're actually used.
Eclipse
A: 
e.James
hah, you got the same idea like me :p
Johannes Schaub - litb
Hey - good idea :)
e.James
+2  A: 

As others stated you cannot do it for reasons they stated too :) You then said you don't want to care about the member construction / destruction in the class containing them. You can use templates for this.

template<typename Type>
struct member {
    boost::shared_ptr<Type> ptr;
    member(): ptr(new Type) { }
};

struct foo;
struct bar {
    bar();
    ~bar();

    // automatic management for m
    member<foo> m;
};

I think the code is self explanatory. If any questions arise, bug me please.

Johannes Schaub - litb
A: 

You could also use the pImpl idiom, e.g.:

//-----------------------
// foo.h
//-----------------------
class foo
{
    foo();
    ~foo();
};


//-----------------------
// bar.h
//-----------------------

class foo;

class bar
{
private:
    struct impl;
    boost::shared_ptr<impl> impl_;
public:
    bar();

    const foo& get_foo() const;
};

//-----------------------
// bar.cpp
//-----------------------
#include "bar.h"
#include "foo.h"

struct bar::impl
{
    foo foo_object;
    ...
}

bar::bar() :
impl_(new impl)
{
}

const foo& bar::get_foo() const
{
    return impl_->foo_object;
}

You still get the benefits of forward declarations, plus you hide your private implementation. Changes to the implementation of bar won't necessarily require compiling all the source files that #include bar.h. The implementation struct itself is self-contained in the .cpp file and here you can declare objects to your hearts content.

You have a small performance hit because of pImpl itself, but depending on the application this might not be a big deal.

I have used the pImpl idiom for large projects and it makes a big difference to compile times. Pity the language cannot handle a truly private implementation, but there you have it.

Rob
A: 

There are really only three alternatives to associate two objects. You already discovered two: embed Foo in Bar, or put Foo on the heap and put a Foo* in Bar. The first requires defining class Foo before defining class Bar; the second merely requires you to forward declare class Foo.

A third option does exist, which I only mention because you specifically exclude both previous options in your question. You can (in your .cpp) create a static std::map. In every Bar constructor you add a Foo to this map, keyed on this. Every bar member can then find the associated Foo by looking up this in the map. Bar::~Bar will call erase(this) to destroy the Foo.

While this keeps sizeof(Bar) unchanged, the actual memory use is higher than including a Foo* in Bar. You still might do this if binary compatibility is a pressing concern, though.

MSalters