C++ nested class/forward declaration issue
Asked Answered
P

6

36

Is it possible to forward-declare a nested class, then use it as the type for a concrete (not pointer to/reference to) data member of the outer class?

I.E.

class Outer;

class Outer::MaybeThisWay   // Error: Outer is undefined
{
};

class Outer
{
 MaybeThisWay x;

 class MaybeThatOtherWay;

 MaybeThatOtherWay y;   // Error: MaybeThatOtherWay is undefined
};
Pukka answered 8/4, 2010 at 13:52 Comment(2)
Your code looks like endless chain of "Outer contains Outer contains Outer contains Outer..."Cavite
possible duplicate of How do I forward declare an inner class?Innocent
M
40

You can't forward-declare a nested class like that.

Depending on what you're trying to do, maybe you can use a namespace rather than a class on the outer layer. You can forward-declare such a class no problem:

namespace Outer {
   struct Inner; 
};

Outer::Inner* sweets;  // Outer::Inner is incomplete so 
                       // I can only make a pointer to it

If your Outer absolutely must be a class, and you can't shoe-horn it into a namespace, then you'll need for Outer to be a complete type in the context where you forward declare Inner.

class Outer
{
   class Inner;  // Inner forward-declared
};  // Outer is fully-defined now

Outer yes;  // Outer is complete, you can make instances of it
Outer::Inner* fun;  // Inner is incomplete, you can only make 
                    // pointers/references to it

class Outer::Inner 
{
};  // now Inner is fully-defined too

Outer::Inner win;  // Now I can make instances of Inner too
Middlebreaker answered 8/4, 2010 at 14:25 Comment(0)
C
15

There is no way to forward declare a nested class without fully specifying the containing class. This little trick kinda fixes the problem though

class Outer_Inner
{
};

class Outer
{
public:
   typedef Outer_Inner Inner;
};

This works for me as in my naming convention Outer_Inner isn't a valid class name, so it's obvious that it refers to an nested class.

You still can't forward declare the nested class like this:

class Outer::Inner;

But at least it can be forward declared with:

class Outer_Inner;

If you don't like the way Outer_Inner looks you could adopt a naming convention for nested classes that better suits your tastes. Outer__Inner, Outer_nested_Inner, etc.

Cake answered 8/4, 2010 at 14:50 Comment(2)
Don't use double underscore - names containing two underscores are reserved to the implementation for any use. See #229283Barkeeper
Is it the same problem I am facing here? #20215240Wil
A
1

If a class has been forward-declared (but you don't have the full definition yet) then you can only declare a pointer to it, because the compiler doesn't yet know the size of the class (nor the names of its fields or methods).

Atlantean answered 8/4, 2010 at 13:58 Comment(0)
O
0

No, but what's wrong with

class Outer {
public:  //or protected or private
    class Inner {
    };

private:
    Inner foo;
};

Forward declaring doesn't make sense here, unless I'm missing something (which is possible seeing as your question is lacking in a lot of details)

Remember, if a class is forward declared then you can only declare references to or pointers to an object of the forward declared type. You can't do anything else with it, including accessing it's members or functions.

Ornithomancy answered 8/4, 2010 at 13:56 Comment(2)
Because Inner is not forwardly declared it is fully defined in there.Notarial
What if you were to reverse the sections here. Maybe some functions in public section use private variables hence need them to be declared but Inner needs to be in private too. How do we allow Inner to be visible in the private section now?Misgive
K
0

If you declare an attribute of type MaybeThatOtherWay, not a reference nor a pointer, the compiler must know the full definition of the class to determine the size of the outer class. Thus, you can't use forward declaration and that kind of field declaration, whether it's a nested class or not.

Kelwunn answered 8/4, 2010 at 14:5 Comment(0)
D
0

If you just need a type as a function parameter or static variable, it could be done on the client side. For example, to receive event notification from Outer:

Interface:

class Client {
public:
private:
    static void gotIt(int event);
    class Helper;
};

Implementation:

#include <outer.hpp>

class Client::Helper {
public:
    static void fromOuter(Outer::Inner const& inner) 
    { 
        gotIt(inner.event());
    }
};
Demello answered 21/12, 2015 at 17:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.