-
May 5th, 2010, 06:02 PM
#1
Another design question
Hi all,
I have a design issue and want to get some feedback on solutions.
I have two classes, let's call them A and B. They have very similar interfaces and are 98% polymorphic. It is in the 2% that they differ which is causing me doubts.
Ideally I would like to derive both these classes from a parent C. Like I say above this will work beautifully for 98% of the time. The issue is that there are a couple of functions A can perform which B can't and vice versa.
Do you think it's still good practice to have these objects inherit from a common class and then deal with the small differences via another solution (eg. Visitor pattern - thanks JohnW)?
Cheers,
BJW
-
May 5th, 2010, 06:12 PM
#2
Re: Another design question
erm, so put the differences in the child/specialised class
-
May 5th, 2010, 06:15 PM
#3
Re: Another design question
The question you need to ask is----are you ever going to treat these two types as if they're actually the same, or do they simply share a lot of common functionality?
If you may at some point want to access their common functionality through a common interface, then public inheritance is absolutely the way to go.
If you don't have that requirement, then you can still move the shared functionality to a third class, but you then have two options, and which one is better depends largely on the nature of the shared capability: either you can give each class (say A and B) a *member* of type C, or you can make both A and B privately inherit from type C. They're similar relationships, but provide slightly different benefits.
-
May 5th, 2010, 06:17 PM
#4
Re: Another design question
@Amleto
Sorry I probably wasn't specific enough about the problem. I want to have a list of objects of type C and treat them generically. Which I can't completely do since there are a couple of operations which can only be done on A or B.
Cheers,
BJW
Last edited by sockman; May 5th, 2010 at 06:20 PM.
Reason: clarify who I was responding to.
-
May 5th, 2010, 06:19 PM
#5
Re: Another design question
@Lindley
Yes, I do plan to treat them as the same type of object - they basically are. It's just that in their specialisation there are a couple of mutually exclusive operations.
Cheers,
BJW
-
May 5th, 2010, 06:33 PM
#6
Re: Another design question
when you need to, downcast with dynamic_cast to access those methods that dont arise from the common base.
Get Microsoft Visual C++ Express here or CodeBlocks here.
Get STLFilt here to radically improve error messages when using the STL.
Get these two can't live without C++ libraries, BOOST here and Loki here.
Check your code with the Comeau Compiler and FlexeLint for standards compliance and some subtle errors.
Always use [code] code tags [/code] to make code legible and preserve indentation.
Do not ask for help writing destructive software such as viruses, gamehacks, keyloggers and the suchlike.
-
May 5th, 2010, 06:38 PM
#7
Re: Another design question
Thanks Russco,
That was my initial plan. I just thought I'd see if anyone had other ideas. The problem I have with that method is I have to query the object to see what type it is. I was hoping to avoid that.
Cheers,
BJW
-
May 5th, 2010, 06:40 PM
#8
Re: Another design question
Another solution is to give the A-only functions to B too, except that when called on B, they do nothing.
And vice versa.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
May 5th, 2010, 07:26 PM
#9
Re: Another design question
Hi monarch_dodra,
I considered this as an option, but I have a hunch it's going to to get me into hot water because whenever I have to perform one of these mutually exculsive operations I will have to call both the operation for A and then for B. I can just see it all becoming a bit messy with the error checking and updating of my program's GUI.
Cheers,
BJW
-
May 5th, 2010, 08:01 PM
#10
Re: Another design question
Originally Posted by sockman
Hi monarch_dodra,
I considered this as an option, but I have a hunch it's going to to get me into hot water because whenever I have to perform one of these mutually exculsive operations I will have to call both the operation for A and then for B. I can just see it all becoming a bit messy with the error checking and updating of my program's GUI.
Cheers,
BJW
Well, to be perfectly fair, we only have A and B to go by, so we're just listing possible solutions. It's up to you to figure out which one best suits your needs.
I'm intrigued by "mutually exculsive operations". These things only A can do, do they have some kind of relationship with the things only B can do?
Depending on your needs, it might be you don't even need a separate A and B class. You could have a single C class with a method called "doSpecialExclusive", and a bool to define if it should choose the A exclusion or the B exclusion. That's just another solution.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
May 5th, 2010, 09:22 PM
#11
Re: Another design question
Another possibility. I let it leak for brevity, its long enough.
Code:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
struct Base
{
virtual void interface() = 0;
virtual void commonfunc() = 0;
virtual ~Base() {}
};
template <class Derived> struct Shim : Base
{
virtual void interface()
{
static_cast<Derived*>(this) -> implementation();
}
};
struct Derived1 : Shim <Derived1>
{
virtual void commonfunc()
{
cout << " Virtual in Derived1 called " << endl;
}
void implementation()
{
cout << " Derived1::implementation called" << endl;
}
};
struct Derived2 : Shim <Derived2>
{
virtual void commonfunc()
{
cout << " Virtual in Derived2 called" << endl;
}
void implementation()
{
cout << " Derived2::implementation called" << endl;
}
};
struct Derived3 : Derived2
{
virtual void commonfunc()
{
cout << " Virtual in Derived3 called" << endl;
}
void implementation()
{
cout << " Derived3::implementation called - Oh dear " << endl;
}
};
int main()
{
vector <Base*> vec;
vec.push_back( new Derived1 );
vec.push_back( new Derived2 );
vec.push_back( new Derived3 );
for_each( vec.begin(), vec.end(),mem_fun( &Base::commonfunc ));
for_each( vec.begin(), vec.end(),mem_fun( &Base::interface ));
//ignore memory leak
return 0;
}
Get Microsoft Visual C++ Express here or CodeBlocks here.
Get STLFilt here to radically improve error messages when using the STL.
Get these two can't live without C++ libraries, BOOST here and Loki here.
Check your code with the Comeau Compiler and FlexeLint for standards compliance and some subtle errors.
Always use [code] code tags [/code] to make code legible and preserve indentation.
Do not ask for help writing destructive software such as viruses, gamehacks, keyloggers and the suchlike.
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
|