我想知道将基子类向下转换为空接口子类的有效性。请参阅下面的示例。基本上我想以通用模板自由方式存储数据(从可以是任何简单算术类型的文件中读取数据。在下面的示例中
std::is_arthmetic<T>
应该始终为真)。
#include <iostream>
#include <vector>
/**
* Mother class holding data.
*/
class NonTypedData
{
std::vector<uint8_t> data_;
public:
NonTypedData(std::size_t size) : data_(size) {}
std::size_t size() const { return data_.size(); }
const uint8_t* get() const { return data_.data(); }
uint8_t* get() { return data_.data(); }
};
/**
* Empty child interface class that handles typed access
*/
template <typename T>
struct TypedData : public NonTypedData
{
static_assert(std::is_arithmetic<T>::value, "TypedData not supported for non arithmetic types.");
const T* get() const { return reinterpret_cast<const T*>(this->NonTypedData::get()); }
T* get() { return reinterpret_cast< T*>(this->NonTypedData::get()); }
std::size_t size() const { return this->NonTypedData::size() / sizeof(T); }
};
template <typename T>
void fill(TypedData<T>& data)
{
for(std::size_t i = 0; i < data.size(); i++) {
data.get()[i] = i;
}
}
template <typename T>
void print(const TypedData<T>& data)
{
for(std::size_t i = 0; i < data.size(); i++) {
std::cout << ' ' << data.get()[i];
}
std::cout << std::endl;
}
int main()
{
NonTypedData data(10*sizeof(int));
fill(static_cast<TypedData<int>&>(data));
print(static_cast<const TypedData<int>&>(data));
return 0;
}
我强烈觉得这是未定义的行为,但我不确定。是吗?
另一方面,我发现这个构造之王非常有用,我觉得可能有一种方法可以在不进入 UB 土地的情况下完成类似的事情。你怎么认为?也许是对
NonTypedData
实例中的 TypedData
实例的引用?
std::vector<uint8_t> data_;
uint8_t* get() { return data_.data(); }
T* get() { return reinterpret_cast< T*>(this->NonTypedData::get()); }
data.get()[i] = i;
data.get()[..]
使用指向 uint8_t
的指针取消引用存储在向量中的 int
数据。这是未定义的行为 - int
数组内没有 uint8_t
。有 uint8_t
值,您可以使用指向 uint8_t
的指针来取消引用它,而不是任何其他类型。
你觉得怎么样?
无效。
如果您想要从
int
得到 uint8_t
,请使用位移位和数学运算。作为最后的手段,如果您想将存储在 uint8_t
数组中的位模式解释为 int
,请使用 memcpy
或 std::bit_cast
(可以实现 memcpy
)。
可能是 TypedData 实例中对 NonTypedData 实例的引用?
没有。