Possible to forward declare a sub class?

Started by
14 comments, last by ChaosEngine 8 years, 5 months ago

Hi guys,

I have a class with a subclass, which is working fine when it is all in-line inside a header file.

If I try to move the subclass to its own source file while leaving a forward declaration (like you would with a function), the compiler throws errors.

Is it not possible to move the subclass into its own CPP file?

Thanks in advance.

Advertisement
A forward declaration just tells the compiler there is a type with that name. The compiler knows neither the size of the type nor any inheritance relationship.

In a nutshell:

class C { ... };
class S;

S myVar; // invalid, the compiler does not know anything about S, not even how much memory it needs
S* myPointer; // no problem, a pointer or reference to an opaque type is fine
C* myBasePointer = myPointer; // invalid, the compiler has no knowledge of any relation between C and S at this point
I cannot decypher what you are doing exactly. This should work: x.h
class Base { ... };

class Derived: public Base { ...};
a.cpp
#include "x.h"
Base::Base() ...
b.cpp
#include "x.h"
Derived::Derived() ...
But this wouldn't throw an error, so you must be doing something else.
Thanks for the replies guys smile.png

This is what I am trying to do and shows how to replicate the error "Incomplete type is not allowed"


#pragma once

class One
{
	int doSomething()
	{
		cTwo = new Two();
		return 0;
	}

	class Two;
	Two* cTwo;
};

// Sub class of 'One'
class One::Two
{
	int test()
	{
		return 0;
	}

}; 
Thanks again for taking a look for me smile.png
That is not what is typically called a subclass. However, the same rules as I listed above still apply to it. You cannot create an instance of Two without its complete definition being known.

What you could do in this case is create a kind of factory function declared in One but implemented where the full definition of One::Two is known.



#pragma once

class One
{
public:
	int doSomething()
	{
		cTwo = createTwo();
		return 0;
	}

	class Two;
	Two* cTwo;

private:
        Two* createTwo();
};

// Implementation in a different file
class One::Two
{
	int test()
	{
		return 0;
	}

}; 

One::Two* One::createTwo()
{
   return new Two();
}

@BitMaster - Extremely nice! That works perfectly. Can't upvote you enough smile.png

Thanks so much for your help.
These kinds of "inner classes" aren't a very popular design choice.
It's much more common to use namespaces, which support forward declarations like so:

namspace Graphics 
{
  class GPU;
  class RenderTarget;
}

What you are doing is more used for private implementation when you have multiple implementation of one class based on a macro for cross plateform.

It's also used to hide variables of one class if you implement one private struct.

Seems when I use BitMaster's example, that I still can't access the members of the internal class. Still reports 'incomplete class'.

Class implementation


// test.h
class One
{
	int doSomething()
	{
		cTwo = createTwo();
		return 0;
	}
	
	class Two;
	Two* createTwo();

public:
	Two* cTwo;
};

// test.cpp
#include "test.h"

// Sub class of 'One'
class One::Two
{
public:
	int Two::test()
	{
		return 77;			// return some test value
	}

};

One::Two* One::createTwo()
{
	return new Two();
}
It compiles ok right up until I try something like this (from the main file.


int result = mOne->cTwo->test();
This results in 'pointer to incomplete class type is not allowed' and 'use of undefined type 'One::Two''
That's what a forward declaration does. You can use the type as a pointer, but if you try to access it's internals, you get a "pointer to incomplete class type is not allowed" error... Because you've only got a forward declaration for the type, and no class definition.

If you want to actually use a class, you've got to include the header that describes it.

This topic is closed to new replies.

Advertisement