我可以继承 std::array 并重载运算符 [] 吗?

Mic*_*olo 2 c++ arrays inheritance

这个问题相当简单。我正在尝试定义一个自定义数组类,它具有普通 std::array 的所有功能,但我想添加使用运算符 [] 和我的代码库中定义的自定义类型的功能。一种选择是将我的类包装在 std::array 周围,例如:

using MyType = double; // just an example

template<typename T, unsigned Size>
class MyArray
{
private:
    std::array<T, Size> m_array{ 0 };
public:
    T& operator [](MyType d) { return m_array[abs(round(d))]; }

    void print()
    {
        for (int i : m_array) {
            std::cout << i << std::endl;
        }
    }
};

int main()
{
    MyType var = 0.5649;
    MyArray<int, 5> vec;
    vec[var] = 1;

    vec.print();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是

0 1 0 0 0 
Run Code Online (Sandbox Code Playgroud)

正如预期的那样。这样做的缺点是我无法访问典型 std::array 接口的所有其余部分。所以我想为什么不让我的数组继承自 std::array:

using MyType = double; // just an example

template<typename T, unsigned Size>
class MyArray : public std::array<T, Size>
{
public:
    // Here I explicitely cast (*this) to std::array, so my operator [] is defined in terms
    // of the std::array operator []
    T& operator [](MyType var) { return std::array<T, Size>(*this)[abs(round(var))]; }
    void print()
    {
        for (int i : (*this)) {
            std::cout << i << std::endl;
        }
    }
};

int main()
{
    MyType var = 2.123;
    MyArray<int, 5> vec{ 0 };
    vec[var] = 1;

    vec.print();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但在这种情况下输出是

0 0 0 0 0
Run Code Online (Sandbox Code Playgroud)

无论值或 var,这都意味着 MyArray 无法正常工作。我究竟做错了什么?继承 std::array 时是否存在根本错误或不可能的情况?

Hol*_*Cat 8

继承本身是合法的,只要您不尝试delete通过指向基类的指针来访问派生类,因为基类缺少虚拟析构函数。

问题是return std::array<T, Size>(*this)[abs(round(var))];创建一个临时对象std::array并返回对其元素的引用,该引用立即变为悬空,因为函数返回时临时对象被销毁。

您想return std::array<T, Size>::operator[](abs(round(var)));调用operator[]基类的 。或者,您可以这样做static_cast<std::array<T, Size> &>(*this)[abs(round(var))];


另请注意,std::array当您有嵌套大括号时,大括号初始化会很不稳定。例如std::array<std::pair<int, int>, 2> x = {{1,1},{1,1}};不起作用,并且需要一组额外的大括号:std::array<std::pair<int, int>, 2> x = {{{1,1},{1,1}}};

但如果您添加继承,这也会停止工作,并且您需要另一对大括号。