Creating and Maintaing Heavy and Light Versions of Classes

J

Jack

Hello

I have a library of calculationally intensive classes that is used both by a
GUI based authoring application and by a simpler non-interactive rendering
application. Both of these applications need to serialise the classes
to/from the same files but only the GUI app needs the full range of class
methods.

Now, the rendering app needs to be ported to multiple OS's but the GUI
doesn't. In order to reduce the time/cost of porting I'd like to create two
versions of the classes - one that only contains the data plus minimum
methods (mostly copy-construct plus serialisation and a few others) and one
with the full range of methods.

My initial thought was to define the simple classes as bases classes and
then derive the full classes from these. However, some of the base classes
would contain members which are themselves classes which need to be
simplified and if I converted these to the simpler classes then it's not
clear how I could recover the full functionality in the derived versions of
these. Hope that makes sense ;-)

Does anyone have any suggestions about how to handle this problem - would
templates be a way around, or maybe smart pointers?

Thanks
Jack
 
D

Derek

Hello

I have a library of calculationally intensive
classes that is used both by a GUI based authoring
application and by a simpler non-interactive
rendering application. Both of these applications
need to serialise the classes to/from the same files
but only the GUI app needs the full range of class
methods.

Now, the rendering app needs to be ported to multiple
OS's but the GUI doesn't. In order to reduce the
time/cost of porting I'd like to create two versions
of the classes - one that only contains the data
plus minimum methods (mostly copy-construct plus
serialisation and a few others) and one with the full
range of methods.

My initial thought was to define the simple classes
as bases classes and then derive the full classes
from these. However, some of the base classes would
contain members which are themselves classes which
need to be simplified and if I converted these
to the simpler classes then it's not clear how I
could recover the full functionality in the derived
versions of these. Hope that makes sense ;-)

Does anyone have any suggestions about how to handle
this problem - would templates be a way around, or
maybe smart pointers?

Thanks Jack

It's hard to make a recommendation without more information, but I
don't think memory management is at the heart of your difficulties, so
I don't see how smart pointers help. Templates might be useful, but
it's hard to say without knowing the details of your classes.

I would just create two independent classes:

struct LightWidget { /*...*/ };

struct Widget
{
explicit Widget(const LightWidget&) { /*...*/ }
};

Use LightWidget when it's all you need (rendering) and create a full
Widget when you have to (GUI). Widget can either be initialized from
data in LightWidget or -- if your design permits -- Widget can store a
LightWidget object and build functionality on top of it, perhaps just
forwarding some common operations (like serialization).
 
J

Jack

Derek said:
It's hard to make a recommendation without more information, but I
don't think memory management is at the heart of your difficulties, so
I don't see how smart pointers help. Templates might be useful, but
it's hard to say without knowing the details of your classes.

I would just create two independent classes:

struct LightWidget { /*...*/ };

struct Widget
{
explicit Widget(const LightWidget&) { /*...*/ }
};

Use LightWidget when it's all you need (rendering) and create a full
Widget when you have to (GUI). Widget can either be initialized from
data in LightWidget or -- if your design permits -- Widget can store a
LightWidget object and build functionality on top of it, perhaps just
forwarding some common operations (like serialization).

Thanks for taking the time...

The problem I have is that Widget itself contains a member of type SubWidget
which also needs to have a LightSubWidget counterpart. So the question is
how to create the Widget/SubWidget object from the
LightWidget/LightSubWidget object - in a way which is reliable and easy to
maintain.

So far the only simple way I can think of achieving this is to bracket all
the heavy code within #ifdefs and set a compiler directive appropriately. It
would be nice if there were some better mechanism for maintaining two
related sets of objects (in separate source files). But is there?

Thanks
Jack
 
R

Robert Frunzke

Jack wrote:
....
Now, the rendering app needs to be ported to multiple OS's but the GUI
doesn't. In order to reduce the time/cost of porting I'd like to create two
versions of the classes - one that only contains the data plus minimum
methods (mostly copy-construct plus serialisation and a few others) and one
with the full range of methods.
....

Why not separate the GUI completely from your "data" classes ?



Robert
 
D

Derek

Jack said:
Thanks for taking the time...

The problem I have is that Widget itself contains a member
of type SubWidget which also needs to have a LightSubWidget
counterpart. So the question is how to create the
Widget/SubWidget object from the LightWidget/LightSubWidget
object - in a way which is reliable and easy to maintain.

You lost me. I don't see problem with reliability or easy of
maintenance if classes have a light core version and a heavier
decorator that adds functionality (and perhaps data), as long as one
can be converted to the other. In my mind the portable core code can
go in the core class and the uglier code that you don't want to port
can inhabit the heavyweight decorator class. If you do this for all
Widgets and SubWidgets, conversion should be straight forward.

But I don't have the whole picture, so I'm willing to take your word
that this approach won't work for you.
So far the only simple way I can think of achieving this
is to bracket all the heavy code within #ifdefs and set a
compiler directive appropriately. It would be nice if there
were some better mechanism for maintaining two related sets
of objects (in separate source files). But is there?

Thanks Jack

My approach requires some refactoring, which may require more effort
than you are able or willing to invest. But if you are using #ifdefs
to build two separate classes from the same source code, then I
suspect a redesign may be what is needed.
 
J

Jack

Derek said:
You lost me. I don't see problem with reliability or easy of
maintenance if classes have a light core version and a heavier
decorator that adds functionality (and perhaps data), as long as one
can be converted to the other. In my mind the portable core code can
go in the core class and the uglier code that you don't want to port
can inhabit the heavyweight decorator class. If you do this for all
Widgets and SubWidgets, conversion should be straight forward.

But I don't have the whole picture, so I'm willing to take your word
that this approach won't work for you.

First off, thanks for your time.

Let me try to illustrate with some pseudo code...

First we have the core classes (I'm omitting LightSubWidget)

class LightWidget
{
public:
LightWidget();
LightWidget(const LightWidget& src);
LightWidget& operator=(const LightWidget& src);
void Serialize( CArchive& ar );
protected:
double m_data;
LightSubWidget m_sub;
};

These classes now have all the functionality needed by the render app.

And now I want to derive the main classes which need more functionality

class SubWidget : public LightSubWidget
{








// Lots of complicated stuff..
void calculate();
void doSomethingTricky();
}

So far so good, but now what about Widget itself?

I can't just have

class Widget : public LightWidget
{
// Lots of complicated stuff..

void useSubWidgets()
{
m_sub.calculate();
}

void useMoreSubWidgets()
{
m_sub.doSomethingTricky();
}
};

because in this case the new members are expecting m_sub to be of type
SubWidget and not LightSubWidget. I'd need to be forever casting m_sub from
LightSubWidget to SubWidget.

What I'd really like is a way of doing this implicitly.

My approach requires some refactoring, which may require more effort
than you are able or willing to invest. But if you are using #ifdefs
to build two separate classes from the same source code, then I
suspect a redesign may be what is needed.

I agree that #ifdefs doesn't feel right but it does at least get around the
problem of having to port a whole load of code that isn't actually used.

Thanks
Jack
 
M

Martijn Lievaart

Hello

I have a library of calculationally intensive classes that is used both by a
GUI based authoring application and by a simpler non-interactive rendering
application. Both of these applications need to serialise the classes
to/from the same files but only the GUI app needs the full range of class
methods.

Now, the rendering app needs to be ported to multiple OS's but the GUI
doesn't. In order to reduce the time/cost of porting I'd like to create two
versions of the classes - one that only contains the data plus minimum
methods (mostly copy-construct plus serialisation and a few others) and one
with the full range of methods.

My initial thought was to define the simple classes as bases classes and
then derive the full classes from these. However, some of the base classes
would contain members which are themselves classes which need to be
simplified and if I converted these to the simpler classes then it's not
clear how I could recover the full functionality in the derived versions of
these. Hope that makes sense ;-)

Does anyone have any suggestions about how to handle this problem - would
templates be a way around, or maybe smart pointers?

I think what you need is the visitor design pattern. This allows you to
define extra operations (but not data!) on the classes in a simple way.
You would keep your classes simple, all the GUI stuff goes into visitors
and have to be included only in the GUI app.

This has the added benefit of decoupling your classes from the GUI used, a
worthwile aproach anyhow. It'll make porting the GUI easier as well.

If your full classes contain extra data, some simple macro's migth help.

#if defined(__Windows)
class GUIWidgetInfo { ... };
#elif defined(__SomeOtherWindowingSystem)
class GUIWidgetInfo { ... };
#elif defined(NOGUI)
class GUIWidgetInfo {};
#else
#error "No GUI defined"
#endif

class Widget {
GUIWidgetInfo gwi_;
...
};

But this is not very elegant. If nothing else, it couples GUI to non-GUI
data. If you need extra state to be kept you might create wrapper objects
that contain these basic objects and use a visitor to add functionality to
these basic objects.

HTH,
M4
 
J

Jack

Thinking a bit more about my problem, it seems to me that what I really need
is a mechanism for declaring data members as virtual in the same way as
member functions can be virtual.

So ideally it would be great if I could have

class LightWidget
{
public:
/* core stuff */

virtual LightSubWidget m_sub;
};


and then define

class Widget : public LightWidget
{
public:
/* tricky stuff */

virtual SubWidget m_sub;
};

But unfortunately that's not allowed

The best I can come up with is

class Widget :public LightWidget
{
public:
Widget() : m_subW ((SubWidget&)m_sub)) {};

/*tricky stuff

SubWidget& m_subW;
};

But would that have any unforeseen side-effects?

Thanks
Jack
 
T

tom_usenet

First off, thanks for your time.

Let me try to illustrate with some pseudo code...

Your problem seems to stem from closely coupling gui and non-gui code.
First we have the core classes (I'm omitting LightSubWidget)

class LightWidget
{
public:
LightWidget();
LightWidget(const LightWidget& src);
LightWidget& operator=(const LightWidget& src);
void Serialize( CArchive& ar );
protected:
double m_data;
LightSubWidget m_sub;
};

The above is all non-gui, so it isn't a "Widget". GUI and non-gui code
should be separated into separate classes and heirarchies. This is a
fundamental tenet of good OO GUI app design (model, view, controller,
etc.) The GUI code depends on the non-GUI code, but not vice-versa.
Instead, how about:

class Data //or Model?
{
public:
Data();
Data(const Data& src);
Data& operator=(const Data& src);
void Serialize( CArchive& ar );
protected:
double m_data;
SubData m_sub;
};

(obviously a better name is required)
These classes now have all the functionality needed by the render app.

And now I want to derive the main classes which need more functionality

class SubWidget : public LightSubWidget
{

Instead, how about:

class SubData
{
//...
};

class SubWidget
{
SubData* data; //can point to Data::m_sub if necessary
//...
};

class Widget
{
SubWidget* subwidget;
Data* data;
//...
};

Remember that inheritence should be a quite rarely used OO tool -
usually containment is far more appropriate. Reserve inheritence for
when you have polymorphic behaviour you want to change, by implenting
an abstract base class. Don't be afraid of writing forwarding
functions to contained objects where appropriate, since you end up
with much more flexible heirarchies that if you use inheritence.

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 

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,159
Messages
2,570,879
Members
47,414
Latest member
GayleWedel

Latest Threads

Top