c++中数组对象的隐式类型转换

Implicit typecasting for array objects in C++

本文关键字:类型转换 对象 数组 c++      更新时间:2023-10-16

我几乎可以肯定这是不可能的,但我还是要问一下。我必须使用基于C的库,它将数字向量定义为浮点数数组,并使用许多算术函数来使用它们。我想创建一个简单的类,它可以很容易地转换为该类型,并添加有用的操作符。让我们看看MWE:

#include <iostream>
using vector_type = float[3];
class NewType
{
public:
    float& operator [](std::size_t i) { return v[i]; }
    const float& operator [](std::size_t i) const { return v[i]; }
    operator vector_type& () { return v; }
    vector_type* operator & () { return &v; }
private:
    vector_type v;
};
int main()
{
    NewType t;
    t[0] = 0.f; t[1] = 1.f; t[2] = 2.f;
    const vector_type& v = t;
    std::cout << "v(" << v[0] << "," << v[1] << "," << v[2] << ")" << std::endl;
    return 0;
}

这可以完美地工作。当我们开始使用数组时,问题就出现了。让我们写一个新的main函数:

int main()
{
    constexpr std::size_t size = 10;
    vector_type v1[size];                   // OK
    NewType v2[size];                       // OK
    vector_type* v3 = v2;                   // No way, NewType* cannot be
                                            // converted to float (*)[3]
    vector_type* v4 =
        reinterpret_cast<vector_type*>(v2); // OK
    return 0;
}

reinterpret_cast可以工作,但它使代码可读性降低,并且vector_typeNewType之间的转换不透明。据我所知,根据c++ 11和c++ 14标准,在使用数组时,不可能使NewType类隐式可浇注。这完全是真的吗?是否有任何类型的警告允许这种转换?

注。: 请不要开始评论使用reinterpret_cast之类的风险。我知道风险,我知道编译器可以添加一些填充,我已经有一些static_assert检查来避免内存问题。

[编辑]我想让这个问题更容易理解。让我们做一个不同的例子:

struct original_vector
{
    float x;
    float y;
    float z;
};
class NewType : public original_vector
{
public:
    /* Useful functions here */
};

如果这是我的情况,一切都会很容易!在C库中使用的类型将是original_vector,我可以创建一个派生类,我可以添加任何类型的方法。

问题是,在我的实际情况下,original_vector 不是一个类/结构,而是一个原始数组!显然,我不能继承它。也许现在我问这个问题的原因更清楚了。div;)

我认为这不是最好的解决方案,但它是我能想到的使用c++ 14功能的最好的解决方案。也许,如果在未来的标准中引入运行时大小的成员分配(c++ 14的建议已被拒绝),将有可能出现更好的解决方案。但是现在…

#include <iostream>
#include <memory>
#include <cassert>
using vector_type = float[3];
class NewType
{
public:
    float& operator [](std::size_t i) { return v[i]; }
    const float& operator [](std::size_t i) const { return v[i]; }
    operator vector_type&  () { return v; }
    vector_type* operator & () { return &v; }
private:
    vector_type v;
};
class NewTypeArray
{
public:
    NewTypeArray() : size(0), newType(nullptr) {}
    NewTypeArray(std::size_t size) : size(size) { assert(size > 0); newType = new NewType[size]; }
    ~NewTypeArray() { if(size > 0) delete[] newType; }
    NewType& operator[](std::size_t i) { return newType[i]; } 
    operator vector_type* () { return static_cast<vector_type*>(&newType[0]); }
private:
    std::size_t size;
    NewType* newType;
};
static_assert(sizeof(NewType) == sizeof(vector_type) and sizeof(NewType[7]) == sizeof(vector_type[7]),
    "NewType and vector_type have different memory layouts");

显然,NewTypeArray可以被修改,实现面向向量的方法、移动构造函数和赋值(就像我的实际代码一样)。NewTypeArray的实例可以直接传递给以vector_type*为参数的函数,并且由于static_assert,应该不会有任何类型的内存管理问题。

#include <iostream>
#include <vector>
typedef std::vector<float> vector_type;
class NewType: public vector_type
{
public:
   void MyMethod() {std::cout << "extending the vector type!" << std::endl;}
};
int main()
{
   NewType myNewTypeVector[10];
   myNewTypeVector[0] = NewType();
   myNewTypeVector[0].push_back(1);
   myNewTypeVector[0].push_back(2);
   vector_type* p = myNewTypeVector;
   std::cout << "Content of my_vector index 0: " << p[0][0] << std::endl;
   std::cout << "Content of my_vector index 1: " << p[0][1] << std::endl;
   std::cout << "Content of myNewTypeVector index 1: " << myNewTypeVector[0][1] << std::endl;
   return 0;
}