By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,758 Members | 1,281 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,758 IT Pros & Developers. It's quick & easy.

Problem with Composition Relation/Forward Referencing.

P: n/a
Hi,

I was trying to implement a composition relation, somthing of the
following type:

class A
{
public:
class B
{
int member_of_B;
};

B b;
// ... some other members;
};
but as the defintion of B is too large I thought of may be writing it
outside. ;). So i modified the class as:
class A
{
class B;
B b;
....
};

class B {
int member_of_B;
};

We have two issues here:

1. anybody including "the .h" (in which i have declared the classes)
would get the type B and can use it. which i didn't intend to allow ;).

2. gcc 3.3.2 gave me an error of this type:

error: field `b' has incomplete type

Am I not allowed to use forward referencing ? What exactly does the
statement

class B;

in definition of A do? Doesn't it introduce the typename in A?

Any suggestions? Am I missing something obvious ?

~ M.

Sep 30 '05 #1
Share this Question
Share on Google+
11 Replies


P: n/a
Milind wrote:
Hi,

I was trying to implement a composition relation, somthing of the
following type:

class A
{
public:
class B
{
int member_of_B;
};

B b;
// ... some other members;
};
but as the defintion of B is too large I thought of may be writing it
outside. ;). So i modified the class as:
class A
{
class B;
B b;
...
};

class B {
int member_of_B;
};

We have two issues here:

1. anybody including "the .h" (in which i have declared the classes)
would get the type B and can use it. which i didn't intend to allow ;).

2. gcc 3.3.2 gave me an error of this type:

error: field `b' has incomplete type

Am I not allowed to use forward referencing ? What exactly does the
statement

class B;

in definition of A do? Doesn't it introduce the typename in A?
A couple of misunderstandings here. The correct way to make the forward
declaration is

class B;

class A
{
B b;
};

class B
{
};

Since class B is declared outside of class A, the forward declaration
must also be outside of class A.

But the second misunderstanding is that an incomplete class (which is
what B is between the forward declaration and the actual declaration) is
only good for a very few things, for instance declaring pointers. In you
code the compiler needs to know the size of B in order to generate code
for A, but it does not know the size of B from just the forward declaration.

The obvious solution to this is just to reverse the order in which you
define your classes.

The other solution would be to rewrite A like this

class B;

class A
{
B* b;
};

By using a pointer you would not need to include the definition of B in
the header file at all. This might also help with your other requirement
that B not be usable by itself.

Any suggestions? Am I missing something obvious ?


Not obvious, but I'd guess you come from a Java background and haven't
quite absorbed yet that objects in C++ are values not references. Easily
the most fundamental difference between Java and C++.

john
Sep 30 '05 #2

P: n/a
> The correct way to make the forward
declaration is

class B;

class A
{
B b;
};

class B
{
};
Well Even that wont work ;( i copy pasted the above stuff and tried to
compile it with g++ 3.3.2 on my Debian box.

That thing apart,
Since class B is declared outside of class A, the forward declaration
must also be outside of class A.
As per my previous posting...
1. anybody including "the .h" .... "which i didn't intend to allow" ;).
I dont want anybody use class B directly, i always want others to use
it as A::B ,i.e as a part of class A. declaring in the way you
suggested will allow everyone else to use it as is.

making it a member would definitely impose using object of class B
inside A's object with this syntax. however, we can't stop ppl from
using bare class B objects.


But the second misunderstanding is that an incomplete class (which is
what B is between the forward declaration and the actual declaration) is
only good for a very few things, for instance declaring pointers.
Yes; pointers work as they have same sizes and we dont allocate memory.
i tried that b4 posting here atfirst and it works fine. that is why i
got confused about forward referencing. if the type is known, why can't
the compiler do a second pass to allocate the mem ?
the compiler needs to know the size of B in order to generate code
for A, but it does not know the size of B from just the forward declaration.
that is why i asked: Am I not allowed to use forward referencing ? What exactly does the
statement

class B;

in definition of A do? Doesn't it introduce the typename in A?\
i mean doesn't the compiler do a second pass to get the size and
stuff??
The obvious solution to this is just to reverse the order in which you
define your classes.
hmmmm ..... but still if i define class B outside class A i will get it
exposed to anyone including the header file.

The other solution would be to rewrite A like this

class B;

class A
{
B* b;
};

By using a pointer you would not need to include the definition of B in
the header file at all. This might also help with your other requirement
that B not be usable by itself.

I dont know how by just declaring a pointer in a class can i restrict
B's usage. could you ellaborate please ?

I did try and implement this with private constructors and friend
functions. However that necessarilly means something else semantically.
i want to implement something like-> A::B always.
Any suggestions? Am I missing something obvious ?


Not obvious


Thnx. cause i was getting pretty worried :)
john


Thnx.
~M

Sep 30 '05 #3

P: n/a
Probably 'pimpl' idiom can help you:

http://www.gotw.ca/publications/mill04.htm

Bye
Fabio
Sep 30 '05 #4

P: n/a
Hey Fabio,

I think the pipl idiom is mostly concerning the avoiding of unnecessary
recompilations and opace interafaces for a class. The example that we
had a couple of days back on the group was regarding the size of a
std::string. i dont exactly believe that the idiom would be useful in
my case.

Thanks.
~M
FabioAng wrote:
Probably 'pimpl' idiom can help you:

http://www.gotw.ca/publications/mill04.htm

Bye
Fabio


Sep 30 '05 #5

P: n/a
Milind wrote:

Hey Fabio,

I think the pipl idiom is mostly concerning the avoiding of unnecessary
recompilations and opace interafaces for a class. The example that we
had a couple of days back on the group was regarding the size of a
std::string. i dont exactly believe that the idiom would be useful in
my case.

It would solve *exactly* your requirement of
1. anybody including "the .h" (in which i have declared the classes)
would get the type B and can use it. which i didn't intend to allow ;).


--
Karl Heinz Buchegger
kb******@gascad.at
Sep 30 '05 #6

P: n/a
Milind wrote:
Hi,

I was trying to implement a composition relation, somthing of the
following type:

class A
{
public:
class B
{
int member_of_B;
};

B b;
// ... some other members;
};
but as the defintion of B is too large
Why "too large"? Did you exceed compiler limits?

I thought of may be writing it outside. ;). So i modified the class as:
class A
{
class B;
B b;
...
};

class B {
int member_of_B;
};

We have two issues here:

1. anybody including "the .h" (in which i have declared the classes)
would get the type B and can use it. which i didn't intend to allow ;).
Well, this is not really a difference. With your original code, everybody
could declare objects of type B. One would just type A::B instead of B.
Now, you might say that this additional typing effort on part of the user
is exactly what you want to impose (sort of as a forced reminder). Well,
that won't fly either since everybody could just do a

typedef A::B B;

at the begining of their file to get rid of that restriction.

2. gcc 3.3.2 gave me an error of this type:

error: field `b' has incomplete type

Am I not allowed to use forward referencing ? What exactly does the
statement

class B;

in definition of A do? Doesn't it introduce the typename in A?


Well, it is a forward declaration inside the scope of A. The compiler should
complain when you do not follow that up by a real declaration inside that
scope.

Also, forward declarations are incomplete. The size of class B is not
deducible from a forward declaration. Thus, the compiler cannot deduce how
much memory is needed for the member object b.
Best

Kai-Uwe Bux
Sep 30 '05 #7

P: n/a
Milind wrote:
The correct way to make the forward
declaration is

class B;

class A
{
B b;
};

class B
{
};

Well Even that wont work ;( i copy pasted the above stuff and tried to
compile it with g++ 3.3.2 on my Debian box.


Well no, it wasn't intended to work, it only corrects the first of your
errors, not the second.

That thing apart,

Since class B is declared outside of class A, the forward declaration
must also be outside of class A.

As per my previous posting...
1. anybody including "the .h" .... "which i didn't intend to allow" ;).

I dont want anybody use class B directly, i always want others to use
it as A::B ,i.e as a part of class A. declaring in the way you
suggested will allow everyone else to use it as is.


OK, well then the only choice you have is to declare B inside of A.

making it a member would definitely impose using object of class B
inside A's object with this syntax. however, we can't stop ppl from
using bare class B objects.
But the second misunderstanding is that an incomplete class (which is
what B is between the forward declaration and the actual declaration) is
only good for a very few things, for instance declaring pointers.

Yes; pointers work as they have same sizes and we dont allocate memory.
i tried that b4 posting here atfirst and it works fine. that is why i
got confused about forward referencing. if the type is known, why can't
the compiler do a second pass to allocate the mem ?


It just doesn't, C++ was designed that way. Makes life easier for the
compiler writers I guess.

john
Sep 30 '05 #8

P: n/a
On Fri, 30 Sep 2005 06:48:50 GMT, John Harrison
<jo*************@hotmail.com> wrote in comp.lang.c++:

[snip]
A couple of misunderstandings here. The correct way to make the forward
declaration is

class B;

class A
{
B b;
};

class B
{
};


ITYM either:

class A
{
B *b;
};

....or:

class A
{
B &b;
};

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Oct 1 '05 #9

P: n/a
>
OK, well then the only choice you have is to declare B inside of A.
Can i have something like: A::B definition for A?
It just doesn't, C++ was designed that way. Makes life easier for the
compiler writers I guess.

Oh.. okay.
john


Oct 1 '05 #10

P: n/a
> Why "too large"? Did you exceed compiler limits?

No; BTW, how do you decide on that ??
Well, this is not really a difference. With your original code, everybody
could declare objects of type B. One would just type A::B instead of B.
oh. i am sorry, i intended to make B private. Then i am under the
impression that doint something like that is going to make a hell lot
of difference...

First, i dont clutter the namespace in which A is declared. i only have
the defintion of B inside A.
Second, i strictly implement the composition relation, Whenever A dies,
B has to die...
Now, you might say that this additional typing effort on part of the user
is exactly what you want to impose (sort of as a forced reminder). Well,
that won't fly either since everybody could just do a

typedef A::B B;


Good trick. but i dont intend to impose any typing overheads (because
initially i will be typing more!!) ;) i just dont want ppl to use B as
you have suggested here. The rule is always make a object of A and we
can then create B inside functions of A.

~M

Oct 1 '05 #11

P: n/a
Milind wrote:
Why "too large"? Did you exceed compiler limits?
No; BTW, how do you decide on that ??


I would trust that the compiler will tell me.

Well, this is not really a difference. With your original code, everybody
could declare objects of type B. One would just type A::B instead of B.


oh. i am sorry, i intended to make B private. Then i am under the
impression that doint something like that is going to make a hell lot
of difference...

Yes, if B is private, it makes a *huge* difference.

So, I take it you are just concerned about the file growing a little too
large. Well, you could put the declaration of B inside A and do the
definition afterwards:
#include <iostream>

class A {

class B {

int i;

void print ( void ) const;
};
};

void A::B::print ( void ) const {
std::cout << i << '\n';
}
Of course, this way you can also put the definitions of a B-methods into a
different file.

First, i dont clutter the namespace in which A is declared. i only have
the defintion of B inside A.
True.

Second, i strictly implement the composition relation, Whenever A dies,
B has to die...


Classes don't die. Objects do. Composition just means that you have an
object of type B as a member of A. It does not mean that there cannot be
any independent B-objects. All member objects of any A-object will die
during the agony of the ambient object. Whether the class B is local or not
is immaterial in this regard.
Best

Kai-Uwe Bux
Oct 1 '05 #12

This discussion thread is closed

Replies have been disabled for this discussion.