派生 class 中非虚函数的 C++ 同名与 `final` 说明符冲突
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++ 打印以下内容 error message:
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()
不会覆盖其基础 classes 中的虚拟函数?我怎样才能使它起作用(--不更改 C::operator()
的名称)?
编辑:正如一些用户所指出的,答案很简单,派生的 class 中的 virtual
-关键字是多余的(而我认为将其排除在外会阻止继承)。然而,我提出这个问题的目的——即贯穿动态和静态继承层次结构的一致接口——可以通过在整个和通过虚函数 apply
:
耦合 classes 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()();
}
如果一个函数在基础 class 中声明为 virtual
,则在派生 class 中隐式地 virtual
使用相同名称和参数列表声明的函数,无论您是否使用 virtual
关键字。您不能使 C::operator()()
非虚拟。
作为覆盖(因为它与基 class 中的虚函数具有相同的签名),覆盖与其基 class 中指定的 final
冲突。
一个解决方法(或者更确切地说是解决方法)是为该函数提供一个默认参数,使其具有不同的类型,因此不是覆盖,更好的方法是修复设计。
派生 class 中与基 class 中的虚函数具有相同签名的函数覆盖基 class 中的虚函数。这使它成为一个虚函数,即使 if/though 派生的 class 中的声明也不使用 virtual
关键字。
无法更改,因此如果您 确实 需要在派生的 class 中有一个同名的函数,它不会覆盖虚拟来自基础 class 的函数(在这个过程中,本身变成虚拟的,在这种情况下,违反了 B
中的 final
)你需要改变函数的签名派生class。这可能意味着不同的名称、不同的参数列表或不同的限定符。尽管我会 极端 谨慎对待后两者——编译器将能够解决您造成的混乱,但许多人类读者可能(很容易)感到惊讶。
如果我正在审查这样的代码,我可能会认为这是一个问题,作者需要提供非常可靠的推理来说明为什么 有必要 得到它批准了。
感觉完全是菜鸟问题,但是为什么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++ 打印以下内容 error message:
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()
不会覆盖其基础 classes 中的虚拟函数?我怎样才能使它起作用(--不更改 C::operator()
的名称)?
编辑:正如一些用户所指出的,答案很简单,派生的 class 中的 virtual
-关键字是多余的(而我认为将其排除在外会阻止继承)。然而,我提出这个问题的目的——即贯穿动态和静态继承层次结构的一致接口——可以通过在整个和通过虚函数 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()();
}
如果一个函数在基础 class 中声明为 virtual
,则在派生 class 中隐式地 virtual
使用相同名称和参数列表声明的函数,无论您是否使用 virtual
关键字。您不能使 C::operator()()
非虚拟。
作为覆盖(因为它与基 class 中的虚函数具有相同的签名),覆盖与其基 class 中指定的 final
冲突。
一个解决方法(或者更确切地说是解决方法)是为该函数提供一个默认参数,使其具有不同的类型,因此不是覆盖,更好的方法是修复设计。
派生 class 中与基 class 中的虚函数具有相同签名的函数覆盖基 class 中的虚函数。这使它成为一个虚函数,即使 if/though 派生的 class 中的声明也不使用 virtual
关键字。
无法更改,因此如果您 确实 需要在派生的 class 中有一个同名的函数,它不会覆盖虚拟来自基础 class 的函数(在这个过程中,本身变成虚拟的,在这种情况下,违反了 B
中的 final
)你需要改变函数的签名派生class。这可能意味着不同的名称、不同的参数列表或不同的限定符。尽管我会 极端 谨慎对待后两者——编译器将能够解决您造成的混乱,但许多人类读者可能(很容易)感到惊讶。
如果我正在审查这样的代码,我可能会认为这是一个问题,作者需要提供非常可靠的推理来说明为什么 有必要 得到它批准了。