Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ nested class in separated header file

Tags:

c++

nested

I would like to move the nested class Inner from Outer.h in a separated header file:

class Outer{
    class Inner{
    public:
        Inner(Outer& o){}
    };

public:
    Outer():i(*this){}
    ~Outer(){}
    Inner i;
};

And for 'main.cpp'

#include "Outer.h"
int main(){
    Outer o;
    return 0;
}

But once I try to place Inner class inside a separated header like this:

class Outer{
    class Inner;

public:
    Outer():i(*this){}
    ~Outer(){};
    Inner i;
};

and place the Inner class in 'Inner.h' like this:

class Outer::Inner{
public:
    Inner(Outer& o){}
};

and add into the main #include 'Inner.h' like this:

#include "Outer.h"
#include "Inner.h"
int main(){
    Outer o;
    return 0;
}

I get the following error from the compiler: Outer.h:10:9: error: field 'i' has incomplete type.

I understand more or less why but I can't find a issue to achieve what I want to do.

like image 320
bou Avatar asked Feb 20 '14 08:02

bou


1 Answers

To create Outer object, the memory layout of the class must be known and in this case, it isn't (exactly because of the incompleteness of Inner).

The way to do this, is to use a pointer, then the forward declaration will work (as the pointer has fixed size and then the memory layout of Outer will be known).


What I mean is:

// header file
class Outer{
    class Inner;

public:
    Outer();
    ~Outer();

    Inner* i;
};

And then, in the source file for class Outer, define

// include header file for Outer and Inner classes

// source file
Outer::Outer()
{
    i = new Inner( *this );
};
Outer::~Outer()
{
    delete i;
};

You need to do this in the source file, because you need to include the header file of class Inner (you cannot include it in the header file directly, because you'll encounter a circular dependency (two header files will include each other), as the header file of Inner will also need the header file of Outer).


This is also known as pImpl idiom - "pointer to implementation" and often Inner is called Impl and the member pImpl or something like this, depending on the used coding convention. The idea is to hide any implementation details, like private/protected members (functions, data).

like image 54
Kiril Kirov Avatar answered Sep 29 '22 11:09

Kiril Kirov