【问题标题】:Access data from base class with the correct typecasting of it derived templated class使用派生模板类的正确类型转换从基类访问数据
【发布时间】:2017-01-03 15:39:33
【问题描述】:

我有以下场景:

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中的值转换为另一种简单的数据类型,如float、int、uchar等。

你们有什么推荐的?

提前致谢!

【问题讨论】:

  • 您是否希望在该 main() 示例中将 int 转换为 float,或者您是否打算确保 100% 仅使用 scalarField 调用 float value = scalarField-&gt;get(index);实例化为ScalarFieldT&lt;float&gt;?
  • 使用static_cast。
  • 所以基本上,您所拥有的只是一个void* 指针,但不知道它可能指向什么?那么恐怕你不能用那个指针做任何有用的事情。你必须重新审视你的设计。
  • 我对您要解决的问题或您必须努力解决的限制条件了解不够,无法提供建议。
  • @JoãoPauloNavarro this 是一个可行的解决方案吗?让我知道,如果它适合你,我会把它放在答案中。它或多或少地完成了您的要求,即从底层缓冲区中提取参数,将其转换为原始类型,然后转换为请求的类型。

标签: c++ c++11 templates


【解决方案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);
}

【讨论】:

    【解决方案2】:

    嗯 - 请不要因为一个可能很愚蠢的答案向我扔石头,但是......

    假设T 仅限于数字数据类型,例如int、long、double、float,我们进一步假设要存储的最大整数值约为 2^53。那么double可以作为数据交换数据类型,任何其他数据类型都可以转换成该数据类型而不会丢失精度。

    然后可以定义virtual double ScalarField::method(int index) = 0,然后在类型化变体中相应地重载它,从实际类型T“向上”转换为double。

    除非允许您将值封装在对象中(例如结构/类值),否则使用“使用双精度作为数据交换数据类型”的以下代码可以工作:

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

    【讨论】:

      猜你喜欢
      • 2017-01-13
      • 1970-01-01
      • 2018-09-18
      相关资源
      最近更新 更多