|
-
November 9th, 2009, 10:54 AM
#1
How to apply a design pattern to a has-a but not a completely has-a case?
I'm not sure if this thread fits this forum, but it's a general C++ design question.
In my case, let's say, object A should have a object B, but B would use some methods exposed by A, so it's not a completely has-a relationship.
If I have B derive from class A, it would work, but strictly B is NOT an A. So, is there a design pattern apply to my case?
thx.
-
November 9th, 2009, 11:07 AM
#2
Re: How to apply a design pattern to a has-a but not a completely has-a case?
If B must call methods upon some particular instance of A, then you could give B a pointer to the A which contains it (or whichever instance is appropriate).
If the methods of A which B needs to call don't apply to any particular A object, you could just make them static. Of course, in this case you need to consider whether it's really appropriate for those methods to be part of class A.
-
November 9th, 2009, 11:38 AM
#3
Re: How to apply a design pattern to a has-a but not a completely has-a case?
 Originally Posted by LifeIsSuffering
...If I have B derive from class A, it would work, but strictly B is NOT an A...?
Have you thought of private inheritance? I'm not sure if you already know but in C++ non-public inheritance doesn't characterize a is-a relationship. Instead, it's known as implemented-in-terms-of.
If this is your case, private inheritance would also allow you to overrid member functions from A. They can easily be exposed through a using directive.
Some links you might find useful:
- http://www.gotw.ca/publications/mill06.htm
- http://www.parashift.com/c++-faq-lit...heritance.html
Last edited by ltcmelo; November 9th, 2009 at 12:38 PM.
Reason: Quoted from original only the significant part concerning my answer.
-
November 9th, 2009, 12:11 PM
#4
Re: How to apply a design pattern to a has-a but not a completely has-a case?
You are in the realms of circular dependency. It may be a problem or may not be but surely it introduces strong coupling that sometimes (most of the times, may be) is avoidable unless you have for example, a logger class that uses an exception class to do its exception handling and the exception class itself uses the logger to do some logging.
It is very easy to fall into this dependency problem. If you can think of another way, that would help but if not then may be you need expand on your classes and what they mean so that others can do the thinking but from the look at your original question, there is no general answer as far as I can see.
Can you help me with my homework assignment?, Before you post!, Use code tags, How to post!, Codeguru technical FAQs, C++ FAQ Lite, Stroustrup: C++ Style and Technique FAQ, Guru of the Week, Comeau C and C++ FAQs, Comeau C++ Templates FAQs, CUJ @ DDJ, Spam threshold
My Blogs : Learning C++ is fun | Abnegator's reflections
Open Threads : C++ Aha! Moments | Nature of work in C++?
-
November 9th, 2009, 12:47 PM
#5
Re: How to apply a design pattern to a has-a but not a completely has-a case?
 Originally Posted by LifeIsSuffering
In my case, let's say, object A should have a object B, but B would use some methods exposed by A, so it's not a completely has-a relationship.
There are many kinds of composition realtionships that doesn't quite fit the standard. One for example is aggregation which expresses a temporary relationship between A and B. An example could be University and Student. A University holds a reference to a Student which holds a reference back to the University.
There's also a situation called a callback. A holds a reference to B and B holds a reference back to A because it wants to know who owns it.
Callbacks can lead to tight coupling between classes but that can sometimes be losened up using interfaces. I've given an example here,
http://www.codeguru.com/forum/showth...77#post1891077
-
November 9th, 2009, 05:30 PM
#6
Re: How to apply a design pattern to a has-a but not a completely has-a case?
Without knowing the exact case it sounds like your design is a bit of a mess. You may need to simply rethink it a bit and perhaps introduce some more objects. Pure virtual base classes can be a lot of help in this respect. With database objects as an example, they can always fit into 3rd normal form, and the same principle applies to objects in general.
-
November 9th, 2009, 09:27 PM
#7
Re: How to apply a design pattern to a has-a but not a completely has-a case?
thx everyone. I know it's definitely a dependency problem.
So, if I don't want to add a 3rd helper object, in this case, I have to let B have a pointer of A, or let B derive from A, actually these 2 solutions are essentially same, inheritance is simpler though.
Even the callback interface solution still have B be aware of A, in nuzzle's sample code.
Last edited by LifeIsSuffering; November 9th, 2009 at 09:30 PM.
-
November 10th, 2009, 01:35 AM
#8
Re: How to apply a design pattern to a has-a but not a completely has-a case?
 Originally Posted by LifeIsSuffering
Even the callback interface solution still have B be aware of A, in nuzzle's sample code.
I didn't want to overcomplicate this particular example, but what you mention can be resolved with another interface D.
To introduce two interfaces like this doesn't seem to amount to much but it isolates the circular dependency and removes this dependency from the concrete subclasses. Besides it's in accordance with the OO rule number one: program to an interface, not an implementation. And this is the mother of all design patterns.
-
November 10th, 2009, 10:38 AM
#9
Re: How to apply a design pattern to a has-a but not a completely has-a case?
 Originally Posted by nuzzle
I didn't want to overcomplicate this particular example, but what you mention can be resolved with another interface D.
To introduce two interfaces like this doesn't seem to amount to much but it isolates the circular dependency and removes this dependency from the concrete subclasses. Besides it's in accordance with the OO rule number one: program to an interface, not an implementation. And this is the mother of all design patterns. 
Sure, program to an interface instead of an implementiaon as more as possible.
But in C++, multiple inheritance may/could introduce some new problem.
Thanks for all, I have to modify my original design accordingly.
-
November 10th, 2009, 12:43 PM
#10
Re: How to apply a design pattern to a has-a but not a completely has-a case?
 Originally Posted by LifeIsSuffering
But in C++, multiple inheritance may/could introduce some new problem.
What would that be? I haven't noticed anything in particular.
-
November 10th, 2009, 08:32 PM
#11
Re: How to apply a design pattern to a has-a but not a completely has-a case?
 Originally Posted by nuzzle
What would that be? I haven't noticed anything in particular.
That's another talk.
Briefly,
1. C inherited from A and B both; (B is pure abstract class, say interface in C++)
2. Created C*.
3. Converted C* to B*, stored it somewhere;
4. converted 3 to an A*, at that moment, the pointer address was not same as orginal, the difference was just 4 bytes away from orginal.
It didn't happen when I tried to prove it with a simple demo but it did in my real code. Then I had to do below,
C* c = (C*)b; // b was result of step 3
A* a = (A*)c; // then worked!
This is really a multi-inheritance problem. My compiler is VC8
-
November 11th, 2009, 12:58 AM
#12
Re: How to apply a design pattern to a has-a but not a completely has-a case?
 Originally Posted by LifeIsSuffering
This is really a multi-inheritance problem.
Sure it's related to multi-inheritance but it's not a problem really if handled correctly.
What you're dealing with is a so called crosscast. That's a downcast followed by an upcast. That's how you solved it. You downcasted from B to C and the upcasted again to A.
Whenever you make a downcast (inluding when it's disguised as a crosscast) you should use one of the newer cast forms, namely a dynamic_cast, like
B* b = c;
A* a = dynamic_cast<A*>(b); // crosscast between B and A of a C object
That should work without problems.
Note that in OO downcasts (and downcasts disguised as crosscasts) should be avoided. It's because they're not type-safe. The compiler cannot decide at compiletime whether the cast will work. It must be done at runtime and it can silently go wrong. Here dynamic_cast can help. It's guaranteed to return a 0 if the cast didn't work. You can check for that and throw an assertion or something so it gets to your attention. But the best thing is to avoid downcasting altogether.
Also note that because upcasts are typesafe the compiler doesn't require you to cast at all in that case. For example the second line in your solution could've looked like this,
A* a = c; // upcasts need not be explicit.
Last edited by nuzzle; November 11th, 2009 at 01:00 AM.
-
November 11th, 2009, 10:44 AM
#13
Re: How to apply a design pattern to a has-a but not a completely has-a case?
 Originally Posted by nuzzle
Sure it's related to multi-inheritance but it's not a problem really if handled correctly.
What you're dealing with is a so called crosscast. That's a downcast followed by an upcast. That's how you solved it. You downcasted from B to C and the upcasted again to A.
Whenever you make a downcast (inluding when it's disguised as a crosscast) you should use one of the newer cast forms, namely a dynamic_cast, like
B* b = c;
A* a = dynamic_cast<A*>(b); // crosscast between B and A of a C object
That should work without problems.
Note that in OO downcasts (and downcasts disguised as crosscasts) should be avoided. It's because they're not type-safe. The compiler cannot decide at compiletime whether the cast will work. It must be done at runtime and it can silently go wrong. Here dynamic_cast can help. It's guaranteed to return a 0 if the cast didn't work. You can check for that and throw an assertion or something so it gets to your attention. But the best thing is to avoid downcasting altogether.
Also note that because upcasts are typesafe the compiler doesn't require you to cast at all in that case. For example the second line in your solution could've looked like this,
A* a = c; // upcasts need not be explicit.
Cool, it worked that way, at least in VC8.
BTW, dynamic_cast may cause porting issue, so I always used strongly casting intead.
Thanks for your reply.
-
November 11th, 2009, 11:34 AM
#14
Re: How to apply a design pattern to a has-a but not a completely has-a case?
 Originally Posted by LifeIsSuffering
Cool, it worked that way, at least in VC8.
BTW, dynamic_cast may cause porting issue, so I always used strongly casting intead.
What I suggested is according to the C++ standard. I doubt that any reasonably modern compiler cannot handle a dynamic_cast. In that case it's so lousy you should avoid it anyway.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|