473,388 Members | 1,417 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,388 software developers and data experts.

Problem with Composition Relation/Forward Referencing.

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
11 2777
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
> 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
Probably 'pimpl' idiom can help you:

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

Bye
Fabio
Sep 30 '05 #4
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
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
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
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
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
>
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
> 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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
by: Dave | last post by:
Hi I'm making a 3D Engine which consists of the class C3DEngine. Part of this engine is a file loader, a class called CMeshLoader. I have made an instance of CMeshLoader in C3DEngine, ie...
4
by: fog | last post by:
Given: class A; and B "has-a" A. The composition relationship between A and B can be implemented in three ways: =================== # 1. class B {
10
by: Florian G. Pflug | last post by:
Hi I installed a postgres-application (which was developed on debian woody) on red hat 9 today, using the postgres 7.3 rpms from redhad. One of my the triggers uses the pg_settings table (more...
2
by: Christopher Benson-Manica | last post by:
Are these terms semantically identical? If so, which is to be preferred when speaking of the construct they describe? -- Christopher Benson-Manica | I *should* know what I'm talking about - if...
2
by: pei_world | last post by:
can anyone help me with these problem, code written correctly except those with * mark. //========================================================================== ===============================...
4
by: Frederik Vanderhaegen | last post by:
Hi, Can anyone explain me the difference between aggregation and composition? I know that they both are "whole-part" relationships and that composition parts are destroyed when the composition...
1
by: tony | last post by:
Hello! I access the class MyComparer in this way. steel_post.Sort(new MeltPracDataComposition.Composition.MyComparer()); You can see the class definition for MyComparer below. As you can see...
4
by: fireball | last post by:
hi, I got confused for a moment about creating data structure for UML composition (strong aggregation) relation one-to-many. I used Rose/DataModeler to do so. <filled_diamond>-------- I...
1
by: Zeljko Bilandzija | last post by:
Hello! I have a problem, and I looking for help if someone can handle this. I use asp.net 2.0, and I create web site which support users from internet (Web Site Administration Tool) and with...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.