隐式虚拟性传播的原因是什么?

What is the reason of implicit virtual-ness propagation?

我只使用 C++ 工作了 2~3 个月,最近我发现了标识符 final,它位于虚函数之后。直到今天,我还相信省略 virtual 会阻止虚拟性的传播,但我错了。它隐式传播。

我的问题是这样的。为什么允许隐式传播?为什么 virtual 的存在不能使函数成为虚函数而 virtual 的存在不能使函数不是虚函数?在某些情况下更好吗?还是在首次引入 虚拟 的那一天?


根据 Clifford's answer,甚至有一个编译器会在缺少 virtual.

时生成警告

why is the virtuality of methods implicitly propagated in c

我希望上面 link 能回答我的问题,但没有。

------------加法------------

有评论询问此功能的用处。 我认为虚函数上的 final 关键字是使函数去虚拟化的原因。该函数不能再被覆盖,因此派生的 class 必须重新声明一个函数,无论它是否具有相同的名称。 如果 final 与去虚拟化不同,请帮助我理解它。 如果 final 没有什么不同,那么从引入 final 的事实来看,去虚拟化的用处是不言而喻的。 我同意强制显式 virtual 会产生错误,但我很好奇是否还有其他原因。

关于为什么某个特定功能存在(或不存在)的答案通常相当困难,因为它变成了猜测和意见的问题。然而,简单的答案可能是 principle of least astonishment。想出一个合理且可靠地工作并且可预测的方案将是困难的。

"devirtualizing" 函数甚至意味着什么?如果在运行时,您在对象上调用 "devirtualized" 函数,它会使用指针的静态类型吗?如果静态类型有虚函数但运行时类型没有,会发生什么?

#include <iostream>

struct A     {  virtual void f() const { std::cout << "A"; }  };
struct B : A {          void f() const { std::cout << "B"; }  };
struct C : B {  virtual void f() const { std::cout << "C"; }  };
struct D : C {          void f() const { std::cout << "D"; }  };

void f(const A& o) { o.f(); }

int main()
{
                // "devirtualized"     real C++

    f(A{});     // "A"                 "A"
    f(B{});     // "A" or "B"?         "B"
    f(C{});     // "C"?                "C"
    f(D{});     // oh god              "D"
}

还有一个事实是,对于绝大多数设计,虚函数必须在整个层次结构中保持虚函数。对所有这些都要求 virtual 会引入各种很难诊断的错误。 C++ 通常会尽量避免使用需要纪律才能正确使用的功能。