469,898 Members | 1,837 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,898 developers. It's quick & easy.

Help needed with design of generic class to handle multiple types

I need to design data storage classes and operators for an image
processing system that must support a range of basic data types of
different lengths i.e. float, int, char, double. I have a template
class that stores the data. The problem with this design is the
inability to treat image data generically- I have a set of specialized
classes with no connection. I'm considering deriving all ImageData<T>
classes from a image data abstract base class with virtual methods for
operations where possible. ImageData methods would then be called on
the base class and be implemented in the specialized template. The
code gets a little ugly when implementing operations with two image
data operands, i.e.

ImageDataBase& operator+(const ImageDataBase& r1, const ImageDataBase&
r2)

In this function I would need to write code to check for all the legal
operand types, using dynamic_cast, and then peform the calculation and
create the result ImageData or throw an exception.

Alternatively I could have an ImageData class that holds a void
pointer and an enum describing the data type.

I'm interested in getting input on the pros and cons of each, also if
there's a better pattern I would like to hear about it.

Jul 23 '05 #1
6 1637
> I need to design data storage classes and operators for an image
processing system that must support a range of basic data types of
different lengths i.e. float, int, char, double. I have a template
class that stores the data. The problem with this design is the
inability to treat image data generically- I have a set of specialized
classes with no connection. I'm considering deriving all ImageData<T>
classes from a image data abstract base class with virtual methods for
operations where possible.
That's not a bad idea. If you need to put ImageData's into a collection
for example, you'll have to use polymorphism.
ImageData methods would then be called on
the base class and be implemented in the specialized template. The
code gets a little ugly when implementing operations with two image
data operands, i.e.

ImageDataBase& operator+(const ImageDataBase& r1, const
ImageDataBase& r2)
Why not a

template <class T>
ImageData<T> operator+(const ImageData<T> &r1, const ImageData<T> &r2);
In this function I would need to write code to check for all the legal
operand types, using dynamic_cast, and then peform the calculation and
create the result ImageData or throw an exception.
What I wrote only accepts same types (two ImageData<int> for example).
You may use two different parameters for the types and the compiler
will give errors if the types cannot be converted.

If you want to disallow legal type conversions, you'll have to do some
checking manually.
Alternatively I could have an ImageData class that holds a void
pointer and an enum describing the data type.
Don't.
I'm interested in getting input on the pros and cons of each, also if
there's a better pattern I would like to hear about it.


Maybe a bit more informations would be useful.
Jonathan

Jul 23 '05 #2

Code4u wrote:
the base class and be implemented in the specialized template. The
code gets a little ugly when implementing operations with two image
data operands, i.e.

ImageDataBase& operator+(const ImageDataBase& r1, const ImageDataBase&
r2)

In this function I would need to write code to check for all the legal
operand types, using dynamic_cast, and then peform the calculation and
create the result ImageData or throw an exception.

Alternatively I could have an ImageData class that holds a void
pointer and an enum describing the data type.

I'm interested in getting input on the pros and cons of each, also if
there's a better pattern I would like to hear about it.


The second approach would be better wherein all the operations can be
accomplished using that I suppose.

Jul 23 '05 #3

Code4u wrote:
I need to design data storage classes and operators for an image
processing system that must support a range of basic data types of
different lengths i.e. float, int, char, double. I have a template
class that stores the data. The problem with this design is the
inability to treat image data generically- I have a set of specialized
classes with no connection. I'm considering deriving all ImageData<T>
classes from a image data abstract base class with virtual methods for
operations where possible. ImageData methods would then be called on
the base class and be implemented in the specialized template. The
code gets a little ugly when implementing operations with two image
data operands, i.e.

ImageDataBase& operator+(const ImageDataBase& r1, const ImageDataBase&
r2)

In this function I would need to write code to check for all the legal
operand types, using dynamic_cast, and then peform the calculation and
create the result ImageData or throw an exception.

Alternatively I could have an ImageData class that holds a void
pointer and an enum describing the data type.

I'm interested in getting input on the pros and cons of each, also if
there's a better pattern I would like to hear about it.


You are of course describing a variant type, that is a an object that
represents a single value of any one of a number of different types.
Needless to say, implementing a variant type poses some challenges and
common pitfalls: dynamic_casts are inefficient, and using void * is
often dangerous.

For a good reference implementation that avoids these sorts of
problems, I would start with the boost variant library. Here's a link
to its documentation: http://boost.org/doc/html/variant.html

Greg

Jul 23 '05 #4
You might want different classes for highly-typed collections vs. a
polymorphic one. One that only takes one type of image data only
should not be allowed to have one of the other ones, but the
polymorphic collection may want more flexibility.

If this is on PC (MFC VS6) beware of dynamic_cast. Extremely expensive
call.

Stuart

Jul 23 '05 #5
On 13 Jul 2005 06:03:55 -0700, "Greg" <gr****@pacbell.net> wrote:

Code4u wrote:
I need to design data storage classes and operators for an image
processing system that must support a range of basic data types of
different lengths i.e. float, int, char, double. I have a template
class that stores the data. The problem with this design is the
inability to treat image data generically- I have a set of specialized
classes with no connection. I'm considering deriving all ImageData<T>
classes from a image data abstract base class with virtual methods for
operations where possible. ImageData methods would then be called on
the base class and be implemented in the specialized template. The
code gets a little ugly when implementing operations with two image
data operands, i.e.

ImageDataBase& operator+(const ImageDataBase& r1, const ImageDataBase&
r2)

In this function I would need to write code to check for all the legal
operand types, using dynamic_cast, and then peform the calculation and
create the result ImageData or throw an exception.

Alternatively I could have an ImageData class that holds a void
pointer and an enum describing the data type.

I'm interested in getting input on the pros and cons of each, also if
there's a better pattern I would like to hear about it.


You are of course describing a variant type, that is a an object that
represents a single value of any one of a number of different types.
Needless to say, implementing a variant type poses some challenges and
common pitfalls: dynamic_casts are inefficient, and using void * is
often dangerous.

For a good reference implementation that avoids these sorts of
problems, I would start with the boost variant library. Here's a link
to its documentation: http://boost.org/doc/html/variant.html

Greg


Greg, the data to be stored is for image processing, a single frame
might be 4k x 4k pixels. Within a single image all the data will be
the same type, so to use a variant for each and every pixel is a
horrible waste of memory. A variant that uses a union would have a
100% overhead when storing an int in a union of int & double. For
Boost variant is looks a good deal worse-

boost::variant<int, double>

has a sizeof()=16

Jul 23 '05 #6
Code4u wrote:
On 13 Jul 2005 06:03:55 -0700, "Greg" <gr****@pacbell.net> wrote:

Code4u wrote:
I need to design data storage classes and operators for an image
processing system that must support a range of basic data types of
different lengths i.e. float, int, char, double. I have a template
class that stores the data. The problem with this design is the
inability to treat image data generically- I have a set of specialized
classes with no connection. I'm considering deriving all ImageData<T>
classes from a image data abstract base class with virtual methods for
operations where possible. ImageData methods would then be called on
the base class and be implemented in the specialized template. The
code gets a little ugly when implementing operations with two image
data operands, i.e.

ImageDataBase& operator+(const ImageDataBase& r1, const ImageDataBase&
r2)

In this function I would need to write code to check for all the legal
operand types, using dynamic_cast, and then peform the calculation and
create the result ImageData or throw an exception.

Alternatively I could have an ImageData class that holds a void
pointer and an enum describing the data type.

I'm interested in getting input on the pros and cons of each, also if
there's a better pattern I would like to hear about it.


You are of course describing a variant type, that is a an object that
represents a single value of any one of a number of different types.
Needless to say, implementing a variant type poses some challenges and
common pitfalls: dynamic_casts are inefficient, and using void * is
often dangerous.

For a good reference implementation that avoids these sorts of
problems, I would start with the boost variant library. Here's a link
to its documentation: http://boost.org/doc/html/variant.html

Greg


Greg, the data to be stored is for image processing, a single frame
might be 4k x 4k pixels. Within a single image all the data will be
the same type, so to use a variant for each and every pixel is a
horrible waste of memory. A variant that uses a union would have a
100% overhead when storing an int in a union of int & double. For
Boost variant is looks a good deal worse-

boost::variant<int, double>

has a sizeof()=16


As the example of the + operator above makes clear, the variant types
in question are on the order of an instance of an ImageData<int>
versus an ImageData<double> and not on the level of ints and doubles.
It's also unlikely that objects with significant storage requirements
will be passed around by value in any case, and the size of the variant
type is not all that important. After all, there is no requirement that
a variant type be value-based, it could just as easily reference the
stored type via a reference wrapper for example. Nor do varant types
that store by value always have constant storage needs. A
template-based variant class can vary its compile-time size based on
the type it is actually storing.

The most important issue though is the question of a compile-time
versus a run-time implementation. The strength of the Boost variant
type is that it requires that each cross pairing of types be either
explicitly handled (or explicitly ignored) by the programmer or the
program will fail to compile.

By covering all the possible combinations at compile-time, there is
little room left for undefined behavior to happen at runtime. And by
performing the computations up front and before they are needed, it has
the added advantage of lower overhead than a runtime implementation
relying on dynamic-casts and polymorphism. In other words, a
compile-time implementation is not only safer than a runtime version -
it is faster as well.

Greg

Jul 23 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

67 posts views Thread by Steven T. Hatton | last post: by
10 posts views Thread by Robert | last post: by
4 posts views Thread by Tarun Mistry | last post: by
9 posts views Thread by Marc De Schrijver | last post: by
3 posts views Thread by =?Utf-8?B?RnJhbmsgVXJheQ==?= | last post: by
2 posts views Thread by hcaptech | last post: by
reply views Thread by Salome Sato | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.