Reputation: 543
I have the following scenario:
class ScalarField
{
void* _buffer; //Array for data.
};
And a derived class:
template <typename T>
class ScalarFieldT : public ScalarField
{
ScalarFieldT(int size)
{
_data = new T[size];
_buffer = _data;
}
T& get(int index)
{
return _data[index];
}
T* _data; // Typed array for data
};
Notice that T
can assume only basic types such float, int, double and so on.
This is a very old legacy code, so I don't have too much flexibility to adjust it properly doing a better design. What a need to do is to access the data from ScalarField::_buffer
with the correct typecasting of it derived class.
Something like this:
void main()
{
int n = TOTAL_SIZE;
ScalarFieldT<int> typedScalarField(n);
ScalarField* scalarField = &typedScalarField;
// This is what I need to do:
int index = ELEMENT_INDEX;
float value = scalarField->method(index); // Get the value from base class correctly converted from int to float, for example.
}
The point is, I only have access to the base class abstraction, but I need to get the value from _buffer
converted to another simple data type, such float, int, uchar, etc.
What do you guys recommend?
Thanks in advance!
Upvotes: 1
Views: 86
Reputation: 50540
You can use a type that provides a set of cast operators as a return type for method
.
It follows a minimal, working example:
#include<memory>
class ScalarField {
protected:
struct Value {
virtual operator float() const = 0;
virtual operator int() const = 0;
// ...
};
public:
virtual const Value & method(int i) = 0;
protected:
void* buffer;
};
template <typename T>
class ScalarFieldT : public ScalarField {
struct TValue: Value {
TValue(T value): value{value} {}
operator float() const override { return float(value); }
operator int() const override { return int(value); }
// ...
private:
T value;
};
public:
ScalarFieldT(int size) {
data = new T[size];
buffer = data;
}
T& get(int index) {
return data[index];
}
const Value & method(int i) {
std::make_unique<TValue>(data[i]);
}
private:
std::unique_ptr<Value> value;
T* data;
};
int main() {
ScalarFieldT<int> typedScalarField(10);
ScalarField* scalarField = &typedScalarField;
float f = scalarField->method(2);
int i = scalarField->method(5);
}
Upvotes: 1
Reputation: 35154
Hm - please don't throw stones on me for a probably silly answer, but...
Let's assume that T
is restricted to numeric data types, e.g. int
, long
, double
, float
, and let's further assume that the largest integral value to be stored is about 2^53. Then double
could serve as an data exchange data type, to which any other data type can be converted without losing precision.
Then one could define virtual double ScalarField::method(int index) = 0
, which is then overloaded accordingly in the typed variants, which do an "up"-cast from actual type T
to double.
Unless you are allowed to encapsulate the values in an object (e.g. struture/class Value), the following code using the "use double as data exchange data type" could work:
class ScalarField
{
public:
void* _buffer; //Array for data.
virtual double method(int index) = 0;
};
template <typename T>
class ScalarFieldT : public ScalarField
{
public:
ScalarFieldT(int size)
{
_data = new T[size];
_buffer = _data;
}
virtual double method(int index) { return get(index); }
T& get(int index)
{
return _data[index];
}
T* _data; // Typed array for data
};
Upvotes: 0