Hi Everyone,
I have a design-/implementation-related question for you all.
In practical usage of C++, especially when processing image or audio data
with 3rd party libraries, there often arises the situation in which a memory
location has to be interpreted as a collection of values of a specific data
type. For example, imagine an audio API that returns void* in a request to
GetSamples(). A simple loop outputting each sample may be:
if (BytesPerSample == 1)
{
// Single byte case (1 - 8 bits per sample)
ty1ByteType* pAudioBuffer =
reinterpret_cast<ty1ByteType*>(AudioData.GetSample s());
for (int SampleNo = 0; SampleNo < NumberOfSamples; SampleNo++)
{
cout << SampleNo << ": " << *(pAudioBuffer++) << endl;
}
}
else if (BytesPerSample == 2)
{
// Double byte case (9 - 16 bits per sample)
ty2ByteType* pAudioBuffer =
reinterpret_cast<ty2ByteType*>(AudioData.GetSample s());
for (int SampleNo = 0; SampleNo < NumberOfSamples; SampleNo++)
{
cout << SampleNo << ": " << *(pAudioBuffer++) << endl;
}
}
else
{
throw ... // Unsupported byte depth
}
Obviously the repeated code is thoroughly undesirable. The code could be
modified so that the processing loop occurs on the outside and the pointer
is cast at each iteration, but this isn't desirable either. As further
depths are supported, the problem snowballs.
I am wondering how other people have addressed this oft occurring problem. I
would like to write the processing code only once and, preferably,
initialise the pointer once also. Initially I thought of writing a
template-based hierarchy, that would allow the following approach:
CMyPointer* pAudio = CMyPointer::CreateInstance(Audio.GetSamples(),
ByteDepth);
CMyPointer& pAudioBuffer = *pAudio;
for (int SampleNo = 0; ...)
{
cout << ... << *(pAudioBuffer++) ...
}
delete pAudio;
To do this, CMyPointer would need to be an abstract non-template-based class
presenting the 'named constructor' CreateInstance and pure virtual pointer
functions. CreateInstance would return the correct typed instance of the
subclass CMyTypedPointer<DATA_TYPE> pointing to the given address using a
datatype of the appropriate byte depth. The problem here arises when
considering the operator*() function in the base class - because this is not
a template-based class, a specific return type has be given which would
differ in instances of the base classes.
What solutions to this scenario have people employed? Of course, it would be
further preferable to cast the memory to any arbitrary type, including
objects.
Many thanks.
Lucy x