![](/img/trans.png)
[英]C++ Inheritance accessing a non-virtual function in derived class from base class pointer
[英]C++ same name for non-virtual function in derived class conflicts with `final` specifier
这有一个完整的新手问题的感觉,但是当将final
说明符用于B::operator()
时,为什么以下代码没有编译?
struct A
{
virtual void operator()() const = 0;
};
// the CRTP-component is not really necessary here
// but it possibly makes more sense in that it could be applied like this in reality
//
template<typename Derived>
struct B : A
{
virtual void operator()() const override final
{
static_cast<Derived const&>(*this).operator()();
}
};
struct C : B<C>
{
void operator()() const
{
//do something
}
};
int main()
{
C()();
}
G ++打印以下错误消息 :
main.cpp:17:14: error: virtual function 'virtual void C::operator()() const'
void operator()() const
^
main.cpp:9:22: error: overriding final function 'void B<Derived>::operator()() const [with Derived = C]'
virtual void operator()() const override final
^
我会以为它可以工作,因为非虚拟C::operator()
不会在其基类中覆盖虚拟函数? 我如何才能使用它(在不更改C::operator()
名称的情况下)?
编辑 :正如几个用户所指出的,答案很简单,派生类中的virtual
-keyword是多余的(而我认为将其保留会阻止继承)。 但是,我提出这个目标的目的是在整个动态和静态继承层次结构中实现一致的接口,可以通过在整个过程中使用非虚拟operator[]
来解决,并通过一个虚拟函数apply
耦合类A
和B
:
struct A
{
void operator()() const
{
this->apply();
}
protected:
virtual void apply() const = 0;
};
template<typename Derived>
struct B : A
{
void operator()() const
{
static_cast<Derived const&>(*this).operator()();
}
protected:
virtual void apply() const override final
{
this->operator()();
}
};
struct C : B<C>
{
void operator()() const
{
//do something
}
};
int main()
{
C()();
}
如果在基类中将函数声明为virtual
函数,则无论您是否使用virtual
关键字,在派生类中声明具有相同名称和参数列表的函数都是隐式virtual
函数。 您不能使C::operator()()
是非虚拟的。
派生类中的功能与基类中的虚函数具有相同签名的函数会覆盖基类中的虚函数。 即使/尽管派生类中的声明不使用virtual
关键字,这也使其成为虚拟函数。
这是无法更改的,因此,如果您确实需要在派生类中拥有一个具有相同名称的函数,并且该函数不覆盖基类中的虚函数(并且在此过程中,请成为虚函数本身,在这种情况下,违反B
的final
),您需要在派生类中更改函数的签名。 这可能意味着不同的名称,不同的参数列表或不同的限定词。 不过,我会非常谨慎地对待后两者-编译器将能够整理出您造成的混乱,但是许多人类读者可能(非常容易)感到惊讶。
如果我正在审查这样的代码,可能会把它当作一个问题,并且作者将需要提供非常扎实的理由,说明为何确实有必要使它获得批准。
作为覆盖(因为它与基类中的虚函数具有相同的签名),所以覆盖与基类中指定的final
冲突。
一种解决方法(或更确切地说,解决方法)是为该函数提供默认参数,以使其具有不同的类型,因此不能覆盖,更好的方法是修复设计。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.