2017-01-02 2 views
1

У меня есть следующий сценарий:Доступ к данным из базового класса с правильным типажей его производным шаблонный класс

class ScalarField 
{ 
    void* _buffer; //Array for data. 
}; 

И производный класс:

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 
}; 

Обратите внимание, что T может принимать только основные типы такие float, int, double и так далее.

Это очень старый унаследованный код, поэтому у меня нет слишком большой гибкости, чтобы правильно его отрегулировать, делая лучший дизайн. Что нужно сделать, так это получить доступ к данным от ScalarField::_buffer с правильным приведением в соответствие его производного класса.

Что-то вроде этого:

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.  
} 

Дело в том, у меня есть только доступ к базовому классу абстракции, но мне нужно, чтобы получить значение из _buffer преобразуется в другой простой тип данных, такой поплавок, INT, uchar и т. д.

Что вы, ребята, рекомендуете?

Заранее благодарен!

+0

Хочешь ли ты 'int' быть отлит как' float' в том, что 'основные()', например, или Вы намерены обеспечить 100%, что ' float value = scalarField-> get (index); 'будет когда-либо вызываться с помощью scalarField, который создается как« ScalarFieldT '? – Frank

+0

Используйте 'static_cast'. –

+0

В момент, когда у вас есть 'ScalarField *' в руке, знаете ли вы фактический тип элементов, на которые указывает '_buffer'? Другими словами, знаете ли вы 'T' для' ScalarFieldT ', из которых этот конкретный экземпляр является подобъектом базового класса? Без этого вам, к сожалению, не повезло. Если вы посмотрите на «ScalarField» самостоятельно, вы не сможете определить, указывает ли '_buffer на массив' int 'или массив' float ', но, конечно, фактические биты в массиве должны были бы быть интерпретируются очень по-разному для этих двух случаев. –

ответ

0

Hm - пожалуйста, не бросайте камни на меня за наверное глупый ответ, но ...

Давайте предположим, что T ограничивается числовыми типами данных, например, int, long, double, float, и предположим далее, что наибольшее целое значение, которое необходимо сохранить, составляет около 2^53. Тогда double может служить типом данных обмена данными, к которому любой другой тип данных может быть преобразован без потери точности.

Затем можно было определить virtual double ScalarField::method(int index) = 0, который затем перегружен соответственно в типизированных вариантах, которые выполняют «вверх» -каст от фактического типа T, чтобы удвоить.

Если вы не разрешено инкапсулировать значения в объекте (например, Struture/класса Value), следующий код с помощью «использовать двойной как тип обмена данными данных» может работать:

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 
}; 
1

Вы можете использовать тип, который предоставляет набор операторов литья в качестве возвращаемого типа для method.
вытекает минимальный, рабочий пример:

#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); 
} 
Смежные вопросы