depandancy and forward declarations

Started by
10 comments, last by NotAYakk 14 years, 11 months ago
I have got the follwoing to work;

//A.h

#pragma once

#include "B.h"
class B;

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

	B* bPointer;

	int getID();
	void func();
};


//B.h

#pragma once

#include "A.h"
class A;

class B
{
public:
	B();
	~B();
	
	A* aPointer;

	int getID();
	void func();
};

#include "A.h"

A::A(void)
{
}

A::~A(void)
{
}


int A::getID(){
	return 20;
}

void A::func(){
	bPointer->getID();
}
#include "B.h"

B::B(void)
{
}

B::~B(void)
{
}

int B::getID(){
	return 20;
}

void B::func(){
	aPointer->getID();
}
But what if i wanted to use the A and B variables in the above classes by value? such as;

//A.h

#pragma once

#include "B.h"
class B;

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

	B b;

	int getID();
	void func();
};

and

//B.h

#pragma once

#include "A.h"
class A;

class B
{
public:
	B();
	~B();
	
	A a;

	int getID();
	void func();
};

How would that work? even when included the headers, i still get the error that the values cant be defined.
Advertisement
That can't work. If an A contains a B and a B contains an A, then an A would have to contain an A by value, which means that A would need to be infinitely large.
The maximum you can get is to make them references, e.g.

class A;class B {    A &a};


It is interesting that the unknown size of class A (and vice versa) does lead to more implications, like you cannot declare an array of class A as long as A is not defined, or use the sizeof operator. See this. Basically, you can't do anything that requires the compiler to know the exact size of the underlying type (whereas it allways knows the size of a pointer/reference).
So when using forward declarations as above, you always have to use a reference or pointer?
Quote:Original post by SiCrane
That can't work. If an A contains a B and a B contains an A, then an A would have to contain an A by value, which means that A would need to be infinitely large.

Or zero in size! (yes yes, that is a purely theoretical snark that doesn't apply in this situation)
Quote:Original post by NotAYakk
Quote:Original post by SiCrane
That can't work. If an A contains a B and a B contains an A, then an A would have to contain an A by value, which means that A would need to be infinitely large.

Or zero in size! (yes yes, that is a purely theoretical snark that doesn't apply in this situation)


Not blessed by standards, I think.
Quote:Original post by maya18222
#include "B.h"
class B;

Why do you include B.h, and then forward declare B? That's kind of redundant. You should include B.h in A.cpp instead, and A.h in B.cpp. That way you decrease the number of includes in your header files, which is a good thing.
(Note: this is a ridiculously theoretical discussion that might be complete clap-trap. Not responsible for any brain damage resulting from reading it.)

Quote:Original post by phresnel
Quote:Original post by NotAYakk
Quote:Original post by SiCrane
That can't work. If an A contains a B and a B contains an A, then an A would have to contain an A by value, which means that A would need to be infinitely large.

Or zero in size! (yes yes, that is a purely theoretical snark that doesn't apply in this situation)
Not blessed by standards, I think.

So the idea would be something like this:
struct A {  B b;};struct B {  A a;};

Both A and B would have size 1. (void*)&(b.a) == (void*)B(b) == (void*)&(a.b) == (void*)&(a.b.a.b.a.b.a.b.a.b).

So, assuming the rule that you need a complete class to instantiate an instance of a class was eliminated... would the above be legal?

sizeof(A) == sizeof(B) == 1.

sizeof(A) == sum(sizeof(contents of A)).

It passes the various POD tests (memory layout is indeed consistent). In fact, the POD test demands that &(a.b.a) == &(a) (or, more specifically:
A a;
B* b = reinterpret_cast<B*>(&a);
A* a2 = reinterpret_cast<A*>(b);
then:
a2 == &a
is true.

I'm not sure how this would actually be useful (if it was allowed). You could use it as a form of infinite type loop? Where each recursive function's call's choice is moderated by the type of a passed in substructure.

It is definitely pathological.
Quote:Original post by NotAYakk
(Note: this is a ridiculously theoretical discussion that might be complete clap-trap. Not responsible for any brain damage resulting from reading it.)

(Okay.)

Quote:
Quote:Original post by phresnel
Quote:Original post by NotAYakk
Quote:Original post by SiCrane
That can't work. If an A contains a B and a B contains an A, then an A would have to contain an A by value, which means that A would need to be infinitely large.

Or zero in size! (yes yes, that is a purely theoretical snark that doesn't apply in this situation)
Not blessed by standards, I think.

So the idea would be something like this:
*** Source Snippet Removed ***
Both A and B would have size 1. (void*)&(b.a) == (void*)B(b) == (void*)&(a.b) == (void*)&(a.b.a.b.a.b.a.b.a.b).

Upon which you couldn't depend. As far as I am informed, different instances require different addresses when asked by operator&(T).

Or do you want to tell us that a member of a class' member should be that [outer] class? In that case, you should use a reference-type, not a value-type.

Quote:
It passes the various POD tests (memory layout is indeed consistent). In fact, the POD test demands that &(a.b.a) == &(a)

I don't understand what your whole post has to do with my answer ("size zero not required by standards") onto your statement.

Quote:
I'm not sure how this would actually be useful (if it was allowed). You could use it as a form of infinite type loop? Where each recursive function's call's choice is moderated by the type of a passed in substructure.

Some languages support lazy-evaluation, which leads to lists that have infinite size, but which are only unfolded to the element that is demanded. This allows for some elegant algorithms. Look at Haskell. Such algorithms could then for example be implemented in C++ using our hypothetical device.

Quote:It is definitely pathological.

As often as you say "pathological", as often I fail to understand what you want to say with it. It does not seem to be internet slang either. Is that some kind of local slang where you live?
Quote:Original post by phresnel
Quote:Original post by NotAYakk
It is definitely pathological.

As often as you say "pathological", as often I fail to understand what you want to say with it. It does not seem to be internet slang either. Is that some kind of local slang where you live?


Try looking here. It's definitely not a local phenomenon.

This topic is closed to new replies.

Advertisement