尽管覆盖但编译错误

Compile error despite override

抱歉,如果这是一个如此简单的问题,我肯定有一些我不了解 c++ 中的继承、virtualoverride 的地方。在下面的示例中,我得到了一个与虚拟方法相关的编译时错误,我专门重写了该虚拟方法以避免在子 class 中出现此类错误。难道我做错了什么?

#include <array>
#include <deque>

template <class T, class C>
struct foo
{
    virtual const C& data() const =0;

    inline virtual T& operator[] ( unsigned n ) const
        { return const_cast<T&>( data()[n] ); }
};

/**
 * The implementation of foo::operator[] is useful for classes inheriting
 * with simple sequence containers like:
 *  foo<T,std::deque<T>>, foo<T,std::vector<T>>, ..
 *
 * But the following requires operator[] to be redefined:
 */

template <class T, unsigned N>
struct baz
    : public foo<T, std::deque<std::array<T,N>> > 
{
    typedef std::deque<std::array<T,N>> data_type;
    data_type m_data;

    inline const data_type& data() const 
        { return m_data; }
    inline virtual T& operator[] ( unsigned n ) const override
        { return const_cast<T&>( data()[n/N][n%N] ); }
};

int main()
{
    baz<double,3> b; // throws an error relative to foo::operator[] depsite override
}

编辑 1 错误:

clang++ -std=c++0x -Wall virtual_operator.cpp -o virtual_operator.o
virtual_operator.cpp:11:12: error: const_cast from 'const value_type' (aka 'const std::__1::array<double, 3>') to 'double &' is not allowed
                { return const_cast<T&>( data()[n] ); }
                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
virtual_operator.cpp:26:8: note: in instantiation of member function 'foo<double, std::__1::deque<std::__1::array<double, 3>, std::__1::allocator<std::__1::array<double, 3> > > >::operator[]'
      requested here
struct baz
       ^
1 error generated.

编辑 2 我认为这是问题的一部分;如果编译失败是因为 foo::operator[] 仍然可以在 baz 中调用,那么如果我 foo::operator[] 声明为虚拟的(即, 隐藏而不是覆盖)?

问题在于,虽然您只打算在 baz 实例上调用派生的 operator[] 函数,但编译器仍需要为基础 class 生成代码,因为该函数仍然可以在 baz 个实例上调用。在这种情况下,生成该代码会导致类型错误,因为您正试图将 const std::array<double,3> 转换为 double&.

为了解决这个问题,您应该在层次结构的不同部分定义一个运算符,该运算符将适用于其所有 children,就像这样(删除了 non-pertainent 内容):

template <class T, class C>
struct foo
{
    inline virtual T& operator[] ( unsigned n ) const = 0;
};

template <class T>
struct bar
    : public foo<T,std::deque<T>>
{
    inline virtual T& operator[] ( unsigned n ) const override
        { return const_cast<T&>( data()[n] ); }
};

template <class T, unsigned N>
struct baz
    : public foo<T, std::deque<std::array<T,N>> >
{
    inline virtual T& operator[] ( unsigned n ) const override
        { return const_cast<T&>( data()[n/N][n%N] ); }
};

这样,如果您以后有任何其他版本要添加,您可以从 bar 或 baz 派生,而不需要定义运算符 per-child。