Class Member Variables:instance Vs pointer

M

Mon

I am in the process of reorganizing my code and came across and I came
across a problem, as described in the subject line of this posting.

I have many classes that have instances of other classes as member
variables. So including a forward declaration doesnt help, does it?
Faced with these, I had the following options:
-Include the appropriate header in the header file that contains the
class definition that has a member variable that is a class instance
as opposed to a pointer to the class
-Change the member variable from being a class instance to a class
pointer.

I have the following questions:
1) Which approach is *better* and why?
2) If you need to include the header and the forward declaration of
the class doesnt help(which is reasonable) what do you do?
For now, Im using this

#ifndef __FILE_H
#include "File.h"
#endif

Thanks in advance.
 
R

red floyd

Mon said:
#ifndef __FILE_H
#include "File.h"
#endif

Thanks in advance.

include guards usually are in the h file itself

-- my_file.h --
#ifndef MY_FILE_H_
#define MY_FILE_H_
// file contents
#endif
--

Also, you need a different ifndef. Any identifier (preprocessor or otherwise)
with two adjacent underscores (leading or not) is reserved to the
implementation. Similarly, any identifier with a single leading underscore,
followed by a capital letter, is reserved to the implementation. That's why I
used a lone trailing underscore for my sample include guard.
 
T

Thomas Wintschel

Mon said:
I am in the process of reorganizing my code and came across and I came
across a problem, as described in the subject line of this posting.

I have many classes that have instances of other classes as member
variables. So including a forward declaration doesnt help, does it?
Faced with these, I had the following options:
-Include the appropriate header in the header file that contains the
class definition that has a member variable that is a class instance
as opposed to a pointer to the class
-Change the member variable from being a class instance to a class
pointer.

I have the following questions:
1) Which approach is *better* and why?
2) If you need to include the header and the forward declaration of
the class doesnt help(which is reasonable) what do you do?
For now, Im using this

#ifndef __FILE_H
#include "File.h"
#endif

Thanks in advance.

*Better* being a very subjective thing...

In such a situation, I only use a pointer (or a reference, which will also
work with a forward declaration) if I am sharing an instance of a class
among a number of objects or if, for some reason, the instance is created
elsewhere and passed to the constructor.

If an instance belongs solely to a parent object then an instance is what I
use. Using a pointer requires an extra new and delete which conflicts with
my lazy side. Clarity is also a factor - the presence of an instance tells
me that it *belongs to* the parent. A pointer or reference could be
borrowed from elsewhere.

Tom
 
J

Jeff Schwab

Mon said:
I have many classes that have instances of other classes as member
variables. So including a forward declaration doesnt help, does it?
Faced with these, I had the following options:
-Include the appropriate header in the header file that contains the
class definition that has a member variable that is a class instance
as opposed to a pointer to the class
-Change the member variable from being a class instance to a class
pointer.

I have the following questions:
1) Which approach is *better* and why?
2) If you need to include the header and the forward declaration of
the class doesnt help(which is reasonable) what do you do?

I have tried both approaches (composition and association), and I'll
give you a couple of quick reasons why I usually prefer the first.

For a while, I tried to avoid letting any header file include any other
file; this amounts to your "option 2." The advantages of this approach
are minimization of inter-module dependencies, fast compilation, and the
fact that headers don't need those annoying macros to prevent multiple
inclusion, since multpile inclusion is only possible if done explicitly
from an implementaton file.

The downsides to non-including headers are more plentiful. The biggest
drawback is that (in most existing development environments) templates
cannot be used in headers. The extra level of indirection often
complicates the code more than it simplifies; for example, if a class is
really only a wrapper around a member (the Bridge design pattern), each
method of the class must be written explicitly just to forward the
function call. Clients' calls to these forwarding functions often
cannot be inlined, either, since the forwarding functions cannot be
defined in the header.

The alternative, option 1, has a lot of upside. Code is easier to
write, the program's performance is improved, etc. In the case of a
Bridge class wrapping a different class, private inheritance can be
used, and no forwarding functions need be written until they become
necessary for reasons of compatibility with some other module.

The biggest problem option 1 has is the strong coupling between modules.
To ease this pain, I wrote a Perl script to write Makefiles listing
all the dependencies. Compilation still can be very slow, since
changing a single header may require several large implementation files
to be recompiled, even if they do not include the header directly.

Most of the advantages of option 2 can be gained by writing an interface
class, then using a Factory to provide objects implementing the
interface. That way, the "real" class definitions are in implementation
files, and can have non-pointer members.
For now, Im using this

#ifndef __FILE_H
#include "File.h"
#endif

Fyi, those guards usually go inside the header file. Of course,
whatever works for you is okay by me. :)

-Jeff
 
M

Mon

"Also, you need a different ifndef. Any identifier (preprocessor or
otherwise) with two adjacent underscores (leading or not) is reserved
to the
implementation."
Sorry, but I dont quite underrstand what you mean by "reserved to the
implementation", can you elaborate? implementation of what?

"Similarly, any identifier with a single leading underscore,
followed by a capital letter, is reserved to the implementation.
That's why I
used a lone trailing underscore for my sample include guard"

Well is this your coding style or are you speaking with some reference
to some coding guide, if so , please let me know, :)

Thanks.

PS. This is NOT my coding style but is the one followed in my project
by us all as per the directions of our supervisor.
 
M

Mon

Thomas Wintschel said:
*Better* being a very subjective thing...
I agree and hence I am seeking opinions and reasons for the same.
In such a situation, I only use a pointer (or a reference, which will also
work with a forward declaration) if I am sharing an instance of a class
among a number of objects or if, for some reason, the instance is created
elsewhere and passed to the constructor.
I do the same: the same object is being shared among various classes,
so what Im doing at present is:
-Creating an instance in one
-Passing the address(hence pointer to the object) in the constructor
of any other class that needs it.

So far so good, I assume.

If an instance belongs solely to a parent object then an instance is what I
use. Using a pointer requires an extra new and delete which conflicts with
my lazy side. Clarity is also a factor - the presence of an instance tells
me that it *belongs to* the parent. A pointer or reference could be
borrowed from elsewhere.

Tom

I plan to use smart pointers for the same and hence memory leaks etc
is not something I need to worry about for the most part.

This for me is important:"the presence of an instance tells me that it
*belongs to* the parent. A pointer or reference could be borrowed
from elsewhere."
Well IF I follow this , then I guess my current usage would be ok but
would still require the headers to be included( because of the class
instance that has to be created).

So as far as I undersatnd: you suggest that a pointer should be used
if the class with the member isnt the parent of that object. Right?

Thanks.
 
M

Mon

Jeff Schwab said:
Fyi, those guards usually go inside the header file. Of course,
whatever works for you is okay by me. :)

-Jeff

Yes of course, I do use these inclusion gaurds in the header else I
would get like a million linker errors when I include the same header
file in multiple files. I do know that. :)

I need to follow the coding style that is currently being followed
here and that means doing things to keep the homegenity of the code
intact.The inclusion headers are there for the purpose of maybe better
readability or something, I cant argue over this with my team.:)
 
V

Victor Bazarov

Mon said:
"Also, you need a different ifndef. Any identifier (preprocessor or
otherwise) with two adjacent underscores (leading or not) is reserved
to the
implementation."
Sorry, but I dont quite underrstand what you mean by "reserved to the
implementation", can you elaborate? implementation of what?

Implementation of the language, IOW, the compiler.
"Similarly, any identifier with a single leading underscore,
followed by a capital letter, is reserved to the implementation.
That's why I
used a lone trailing underscore for my sample include guard"

Well is this your coding style or are you speaking with some reference
to some coding guide, if so , please let me know, :)

No, it's in the Standard. Every identifier (read: name) that begins
with an underscore and a capital letter (like _Whatever) is _reserved_
by the implementation, IOW, you must _not_ use it.
Thanks.

PS. This is NOT my coding style but is the one followed in my project
by us all as per the directions of our supervisor.

Doesn't make it right...
 
M

Mon

Jeff Schwab said:
I have tried both approaches (composition and association), and I'll
give you a couple of quick reasons why I usually prefer the first.

Do you mean composition and aggregation?
For a while, I tried to avoid letting any header file include any other
file; this amounts to your "option 2." The advantages of this approach
are minimization of inter-module dependencies, fast compilation, and the
fact that headers don't need those annoying macros to prevent multiple
inclusion, since multpile inclusion is only possible if done explicitly
from an implementaton file.
I dont know how feasible it would be to have absolutely NO dependence
between modules and how you implemented the whole thing. :) Because
thus far I havent done anything as you've described.
Multiple Inclusion is ALL I have done in the system that Ive developed
thus far and I cant fathom my world without them. :) Any example of
what you suggested here?
The downsides to non-including headers are more plentiful. The biggest
drawback is that (in most existing development environments) templates
cannot be used in headers. The extra level of indirection often
complicates the code more than it simplifies; for example, if a class is
really only a wrapper around a member (the Bridge design pattern), each
method of the class must be written explicitly just to forward the
function call. Clients' calls to these forwarding functions often
cannot be inlined, either, since the forwarding functions cannot be
defined in the header.

The alternative, option 1, has a lot of upside. Code is easier to
write, the program's performance is improved, etc. In the case of a
Bridge class wrapping a different class, private inheritance can be
used, and no forwarding functions need be written until they become
necessary for reasons of compatibility with some other module.

The biggest problem option 1 has is the strong coupling between modules.
To ease this pain, I wrote a Perl script to write Makefiles listing
all the dependencies. Compilation still can be very slow, since
changing a single header may require several large implementation files
to be recompiled, even if they do not include the header directly.

Most of the advantages of option 2 can be gained by writing an interface
class, then using a Factory to provide objects implementing the
interface. That way, the "real" class definitions are in implementation
files, and can have non-pointer members.

So as I see it: its a toss between choosing to implement an interface
and making the extra effort to gain the advantages of/from Option
1(namely program performance improvement, better readability etc)
vis-a-vis Loose Coupling in Option 2 that doesnt requitre much effort,
I guess forward declarations are all that are needed!

But that raises a question:
Do you think its *really* worth the effort to have interface
definitions/class implemnetations for something that can be done
through just defining a class? I guess it'll depend on the size of the
project? Any thoughts?

Thanks so much for the reply.
 
V

Victor Bazarov

Mon said:
Jeff Schwab <[email protected]> wrote in message

Do you mean composition and aggregation?

Aren't composition and aggregation the same thing?

Jeff means composition when he talks of

struct A { // an 'A' is composed of a 'B' and a 'C'
B b;
C c;
};

And he means association when he talks of

struct A { // an 'A' is associated with a 'B' and a 'C'
B* pb;
C* pc;
};

The former is simpler, the latter is more flexible.

What do you mean by 'aggregation' and what's the difference
between 'composition' and 'aggregation' in your mind?
But that raises a question:
Do you think its *really* worth the effort to have interface
definitions/class implemnetations for something that can be done
through just defining a class? I guess it'll depend on the size of the
project? Any thoughts?

MHO, of course, (and sorry for barging in) is that for dynamic systems
(like plug-ins for your kernel) you cannot help by organise everything
into interface/implementations. So, there are situations when not only
you prefer it, but you cannot avoid it.

If you're talking about situations where a choice exists, there are
probably other factors that determine the selection. Like, for example,
maintainability of the code/system: do you need to recompile/relink
the kernel if your implementation needs to be updated? Of course it
just shows my preference of the plug-in architecture in everything :)

Victor
 
J

Jeff Schwab

Mon said:
Do you mean composition and aggregation?

Yes; I should have said "composition and mere association." Thanks for
correcting me!
I dont know how feasible it would be to have absolutely NO dependence
between modules and how you implemented the whole thing. :) Because
thus far I havent done anything as you've described.
Multiple Inclusion is ALL I have done in the system that Ive developed
thus far and I cant fathom my world without them. :) Any example of
what you suggested here?

I didn't say there were no multiple inclusions, or no dependencies
between modules. I said I didn't let any *header* file include any
other file. The implementation (.cc) files could include all the
headers they wanted. Sorry, I don't have an example I can post.

So as I see it: its a toss between choosing to implement an interface
and making the extra effort to gain the advantages of/from Option
1(namely program performance improvement, better readability etc)
vis-a-vis Loose Coupling in Option 2 that doesnt requitre much effort,
I guess forward declarations are all that are needed!

It's true that option 2 requires less effort on the part of the users of
the module, and in terms of dependency tracking. However, I do think
it's far more effort to implement.
But that raises a question:
Do you think its *really* worth the effort to have interface
definitions/class implemnetations for something that can be done
through just defining a class? I guess it'll depend on the size of the
project? Any thoughts?

It depends a lot on the situation. If you "just define a class," all
the users of the class have to recompile their code every time you
change the implementation of the class. If you go through the effort of
decoupling the interface thoroughly from the implementation, the clients
need only relink, and are much, much happier. Similarly, a vendor of
proprietary libraries might be willing to go to some extra effort to
avoid revealing *any* implementation details. Like I said, though, I
generally use Option 1 these days. :)
Thanks so much for the reply.

Hope it helped!

-Jeff
 
J

Jeff Schwab

Victor said:
Aren't composition and aggregation the same thing?

Jeff means composition when he talks of

struct A { // an 'A' is composed of a 'B' and a 'C'
B b;
C c;
};

And he means association when he talks of

struct A { // an 'A' is associated with a 'B' and a 'C'
B* pb;
C* pc;
};

The former is simpler, the latter is more flexible.

That's exactly what I meant. :) I should have been more careful with
terminology; since "aggregate type" often is used to mean any C++ type
composed of other types, I've taken to using "association" to mean UML
folks call "aggregation."

What do you mean by 'aggregation' and what's the difference
between 'composition' and 'aggregation' in your mind?




MHO, of course, (and sorry for barging in) is that for dynamic systems
(like plug-ins for your kernel) you cannot help by organise everything
into interface/implementations. So, there are situations when not only
you prefer it, but you cannot avoid it.

If you're talking about situations where a choice exists, there are
probably other factors that determine the selection. Like, for example,
maintainability of the code/system: do you need to recompile/relink
the kernel if your implementation needs to be updated? Of course it
just shows my preference of the plug-in architecture in everything :)

I'm told the Solaris kernel lets you drop in drivers as shared objects,
just by putting files in certain places. It's too bad folks like you
didn't write the linux kernel. ;)
 
M

Mon

Implementation of the language, IOW, the compiler.
No, it's in the Standard. Every identifier (read: name) that begins
with an underscore and a capital letter (like _Whatever) is _reserved_
by the implementation, IOW, you must _not_ use it.
Thanks, I will keep this in mind.
Doesn't make it right...

I didnt suggest for a second that it WAS right, all I said was that Im
using it right now as per the directions of the supervisor.
 
M

Mon

Yes; I should have said "composition and mere association." Thanks
for
correcting me!
I thought of just the UML way of defining these terms, now I
understand better. Thanks.

It depends a lot on the situation. If you "just define a class," all
the users of the class have to recompile their code every time you
change the implementation of the class. If you go through the effort of
decoupling the interface thoroughly from the implementation, the clients
need only relink, and are much, much happier. Similarly, a vendor of
proprietary libraries might be willing to go to some extra effort to
avoid revealing *any* implementation details. Like I said, though, I
generally use Option 1 these days. :)


Hope it helped!

-Jeff
Yes it certainly did because I think I must plan a total revamp of a
few classes by defining the interfacce and then the relevant
implementation classes because this code is by no means complete and
is expected to undergo many many revisions in the future, would be
easier on me if I made my life tougher now vs making it harder in the
future when more the code size increases.

Many thanks. :)
 
J

Jeff Schwab

I think I must plan a total revamp of a
few classes by defining the interfacce and then the relevant
implementation classes because this code is by no means complete and
is expected to undergo many many revisions in the future, would be
easier on me if I made my life tougher now vs making it harder in the
future when more the code size increases.

You are wise beyond your years. ;) Good luck.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,157
Messages
2,570,879
Members
47,414
Latest member
djangoframe

Latest Threads

Top