In article <bu**********@news1.ucsd.edu>, E G wrote:
Hi!
I am having problems in designing a class. First, I have a base class
that allocates a 3D data set and allows some other mathematical
operations with it,
What mathematical operations do you need to do ? Think about this carefully,
it's important.
template <typename T> class BasicArray
{
.
.
.
private:
T ***Array;
Why use T*** and not a T* ? What are the advantages of this approach ? Have you
read the FAQ for this forum ?
public:
T operator()(unsigned,unsigned,unsigned);
Should be:
T& operator()(unsigned,unsigned,unsigned);
const T& operator() const(unsigned,unsigned,unsigned);
This class is not useful alone since I have to read the data from files.
The files may contain the information in an 3D array of any C basic type
(i.e., char, short, int, float, etcetera). This is the reason of
creating a template class. I decided to create a second class "Volume"
that handles the I/O and header information and uses BasicArray somehow.
Here's the problem: you don't know what data type is stored in the file at
compile time. So you need to handle this dynamically.
For example:
class FileReader;
class DoubleReader : public FileReader
{
....
};
....
Then the question is, do you always convert the data into a certain type of
BasicArray (BasicArray<double> or BasicArray<int> or even BasicArray<char>
depending on what you need to do with the data) or do you leave the data in
the same format that it's stored on disk ?
You need to think about how your classes are going to be used. Flexibility
may seem like a good thing, but gratuitous flexibility is often actually
just a nuisance. For example, having a "data set of any type" class could
result in worse performance, and create all sorts of nasty problems down
the road when you write your math ops.
Since the information of the basic type in which the information is
represented is stored in the file I cannot inherit Volume from
BasicArray.
Templates and inheritance don't mix that well. If you really did want to
handle this data polymorphically, you would need to derive BasicArray from
some other class:
class BaseArray
{
double operator() ( ..... );
....
};
class BasicArray<T> : public BaseArray
{
};
But then you're going to have one hell of a time doing things like
performing arithmatic ops on mixed types. For example, suppose you "add"
a BasicArray<double> to a BasicArray<int>. What type should the result
be ? You need a double dispatch. Also, if you are to make a variable return
type, it needs to be a polymorphic BaseArray* pointer, not a value.
But that's ugly. So now you need to wrap your BaseArray class in a handle.
You should read a book that discusses handle classes if you haven't yet done
so. Accelerated C++ would be a good start.
Have I convinced you that using an "any-datatype" class for general use is
probably not as good an idea as it may at first seem ?
I was thinking of creating the class Volume with a void *
pointer.
No! That's a horrible way to do it.
You would need
class ArrayHandle
{
BaseArray* impl;
public:
....
};
class BaseArray
{
....
};
template <typename T> class BasicArray : public BaseArray
{
...
};
Then you have to decide how the handle manages your array. Does it reference
count ? Does it deep copy ? Etc.
Then you need to think about how you handle mixed type arithmatic. For example,
does it make sense for the sum of two BasicArray<short> objects to be a
BasicArray<double> object ? You need to write "double dispatch" code which
in itself is a terrible mess.
Now the simplest solution would be to avoid the "any type" nonsense for
anything more complicated than element access and file reading. This way,
you only use "any type" for the limited and probablyt necessary task of
being able to make small changes to large files without changing the data
type of the whole file.
For mathematical operations, the appropriate model will usually be to convert
the on-disk data to an appropriate type. What an "appropriate type" is depends
on what is being done with the data. char is appropriate for a binary mask.
int is appropriate for discrete valued data, and for results of computations
which preserve discreteness (e.g. spatial masking) floating point types are
appropriate for storing the results of floating point computation on int data.
The person using the code for a particular application is the right person
to decide what type of Array is the appropriate one to use.
Sometimes, there may not be a sensible conversion (for example, double->char).
In this case, there should be some way to throw an exception or something,
to tell the programmer using the class that the file open "failed" because
the file was "unsuitable" for their intended use. Again, this must be handled
at runtime since you don't know what will be in the file at compile time.
Cheers,
--
Donovan Rebbechi
http://pegasus.rutgers.edu/~elflord/