Re: Problem with inheritance and arbitrary "features" support (via
templates).
* KRao78:
I have the following C++ design problem and I would really appreciate
any suggestion/solution.
Please notice that my background is not in computer science, so I may
be missing some obvious solution.
The way I usually separate key components in the code is to define
interfaces via abstract classes and pure virtual functions.
Example1:
class B
{
public:
virtual double f( double x ) = 0;
};
class D1 : public B
{
public:
double f( double x ) const
{
return 0.0;
}
};
What's the point of hiding B::f in class D1 (which is still abstract)?
Hm, let's assume that was a typo.
But please, when posting code, copy and paste *working* code.
class D2 : public B
{
public:
double f( double x ) const
{
return 1.0;
}
};
This way I can nicely separate interface from implementation.
This approach is also quite fast (and as what I am working on is a
numerical library this is important :P).
Now, the problem I am facing is the following one.
I have a set of "functionalities" which can be summarized by functions
(defined below) f(), g(), and h()
Notice that all these functions will in general differ in arguments
and return types.
Suppose I have some code that expects a pointer to an object that
implements the functionalities f() and g().
What I would like to do is to being able to pass something which has
"more or equal" functionalities, for example something which supports f
(), g() and h().
To better explain myself here is some code.
Please notice that instead of multiple inheritance I can have used a
"nested intheritance" approach, like in boost::operators. The point
here is that I will never have the case in which f() is the same as g
(). All the features are different.
Te problem is that in order to make this work I need to use
reinterpret_cast as in the example below (so this is not really a
solution):
Example2:
class F {
public:
virtual double f( double x ) = 0;
};
class G {
public:
virtual double g( double x ) = 0;
};
class H {
public:
virtual double h( double x ) = 0;
};
class N {};
template<class T1, class T2=N, class T3=N>
class Feature : public T1 , public T2 , public T3
{
};
Again, please copy and paste *working* code.
You can't inherit directly twice or more from the same class.
template<class T1, class T2>
class Feature<T1,T2,N> : public T1, public T2
{
};
template<class T1>
class Feature<T1,N,N> : public T1
{
};
//Supp for Supports/Implements
class SuppFandG : public Feature<F,G>
{
public:
double f( double x ) { return 0.0; }
double g( double x ) { return 1.0; }
};
class SuppFandH : public Feature<F,H>
{
public:
double f( double x ) { return 0.0; }
double h( double x ) { return 1.0; }
};
class SuppFandGandH : public Feature<F,G,H>
{
public:
double f( double x ) { return 0.0; }
double g( double x ) { return 1.0; }
double h( double x ) { return 2.0; }
};
Here you're into combinatorial nightmare.
But you probably know that.
Perhaps that is the question.
int main()
{
Feature<F,G>* featureFandGPtr;
Feature<F,H>* featureFandHPtr;
Feature<H,F>* featureHandFPtr;
Feature<F,G,H>* featureFandGandHPtr;
SuppFandGandH suppFandGandH;
featureFandGandHPtr = &suppFandGandH;
//featureFandGPtr = featureFandGandHPtr; //Illegal. static_cast
illegal too.
//the reason to do this is that I would like to pass a pointer to an
object
//of type Feature<F,G,H> to a function (or constructor) that expects
a pointer to Feature<F,G>
featureFandGPtr = reinterpret_cast< Feature<F,G>* >
( featureFandGandHPtr );
featureFandHPtr = reinterpret_cast< Feature<F,H>* >
( featureFandGandHPtr );
featureHandFPtr = reinterpret_cast< Feature<H,F>* >
( featureFandGandHPtr );
featureFandGPtr->f( 1.0 );
featureFandGandHPtr->h( 1.0 );
}
Oh my. :-)
Why not just remove those featureThisAndThat classes?
Remember: KISS - Keep It Simple, Stupid.
(You may want to Google or Wikipedia that principle.)
Or I can try to construct a inheritance hierarcy but changing the
definition of Feature but the following example makes the Visual
studio 2008 professional compiler crash, so I cannot test it.
Example 3:
//This will not work, Visual studio 2008 professional crash.
template<class T1, class T2=N, class T3=N>
class Feature : public Feature<T1,T2> , public Feature<T1,T3> , public
Feature<T2,T3>
{
};
template<class T1, class T2>
class Feature<T1,T2,N> : public Feature<T1>, public Feature<T2>
{
};
template<class T1>
class Feature<T1,N,N> : public T1
{
};
What do you want the Feature... classes *for*?
With this approach I still have the problems
1) Feature<F,G> is logically equivalent (for what I want to achieve)
to Feature<G,F> but their types are different.
This can however be solved by some fancy metaprogramming using the MPL
boost library (always "sort" the types), so for simplicity let's
assume this is not a problem.
2) Problem of multiple bases, and I want to avoid virtual inheritance
via virtual bases (performance penalty).
Don't think about performance.
Let the compiler do that.
It's not that it's very much smarter, it may even do plain stupid things, but
whatever it does, by deciding to trust that whatever it does is good enough
*you* will be working smarter. <g>
This is probably solvable by using directives inside the Feature
specializations.
Still I am not 100% sure I can make this work and it will not scale
well for a large number of features.
In fact the number of elements composing the hierarchi is given by the
binomial coefficient, almost factorial:
F - > F (1)
F,G - > FG, F, G (3)
F,G,H -> FGH, FG, GH, FH, F, G, H (7)
Yes.
I would like to know if there is a solution to the design problem
which involves the following conditions:
1) The code should have a runtime performance equivalent to Example 1.
Then use example 1. After correcting it, of course.
2) I want to be able to specify easily some set of features and being
able to "pass in" any pointers to objects that have this (and usually
extra) functionality.
Huh?
3) I want code that depends on features f() and g() not to require re-
compiling whenever I consider a new feature h() somewhere else.
4) I do not want to template everything that want to use such features
(almost all the code). There should be some kind of "separation", see
point 3.
Looking in the (numerical) libraries I have usually found the two
approaches:
1) Define a huge abstract base class B that have f(),g(),h(),......
Problems: whenever I want to add a new feature z(), B has to be
modified, everything needs to be re-compiled (even if this code does
not care about z() at all), all the existing implementations D1,
D2,... of B needs to be modified (usually by having them throw an
exception for z() apart for the new implementation that supports z()).
The solution of enlarging B progressively when I need to add features
is not a good one for the problem at hand, as the featurs f() and g()
are really "as important" as h() and i(), an neither is "more basic"
then the others.
2) Separate all the functionalities and use one pointer for each
functionality.
However, this is cumbersome for the user (in most situations 4 or more
pointers would have to be carried around), and for the problem at hand
this approach is not optimal (here really it is 1 object that may or
may not do something, in fact calling f() will modify the result
obtained by g() and vice-versa).
Thank you in advance for your help.
You're into bad design and should primarily look at that.
It needs total revamping.
But as technical solution for your current design, use one interface class per
function f(), g(), h() (that's essentially your example 2 without the template).
Cheers & hth.,
- Alf
(Just deciding to answer some clc++ posts)