【问题标题】:Compile error despite override尽管覆盖编译错误
【发布时间】:2015-03-22 10:18:22
【问题描述】:

对不起,如果这是一个如此简单的问题,一定有一些我不明白的关于继承的东西,c++ 中的virtualoverride。在下面的示例中,我得到了一个与我特意覆盖的虚拟方法相关的编译时错误,以避免在子类中出现此类错误。难道我做错了什么?

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

EDIT 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.

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

【问题讨论】:

  • 您能否将错误本身添加到问题中?
  • @JosephMansfield 查看编辑
  • bar 是否与问题相关?我认为它只会增加噪音并使其更难阅读。你应该删除它。
  • @Angew 这更好吗?
  • 当然。读者解析和突出问题区域的模板代码减少了 33%。如果我还没有这样做,我当然会赞成:-)

标签: c++ inheritance c++11 polymorphism overriding


【解决方案1】:

问题在于,尽管您只打算在 baz 实例上调用派生的 operator[] 函数,但编译器仍需要为基类生成代码,因为该函数仍可在 baz 实例上调用。在这种情况下,生成该代码会导致类型错误,因为您试图将 const std::array&lt;double,3&gt; 转换为 double&amp;

为了解决这个问题,您应该在层次结构的不同部分定义一个对其所有子级都有效的运算符,就像这样(删除不相关的东西):

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 派生,而无需为每个子项定义运算符。

【讨论】:

  • 如果它被标记为虚拟并且我在子类中提供了覆盖,为什么它需要在基类中为这个特定函数生成代码?在这种情况下有解决方法吗?
  • @Sh3ljohn 它仍然可以调用。是什么阻止了baz::operator[] 打电话给return foo::operator[](n);,甚至是外面的人打电话给b . foo&lt;blah, blah&gt;::operator[] (7)
  • @Angew 好吧,有什么解决方法,还是我应该将运算符声明为纯虚拟运算符并在每个孩子的基础上实现它?
  • 最好将foo 中的版本在层次结构的更下方实现,因为bazfoo 的语义不同。
  • @Sh3ljohn 因为除非需要,否则不会实例化模板和模板成员。不需要未调用的非虚拟函数。对于虚函数,“如果虚拟成员函数不会被实例化,则实现是否隐式实例化类模板的虚成员函数是未指定的。” (C++11 14.7.1/10)
猜你喜欢
  • 1970-01-01
  • 2017-03-16
  • 1970-01-01
  • 1970-01-01
  • 2013-01-20
  • 2023-01-25
  • 2020-07-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多