【问题标题】:In C++, is a function automatically virtual if it overrides a virtual function?在 C++ 中,如果一个函数覆盖了一个虚函数,它会自动成为虚函数吗?
【发布时间】:2024-01-04 05:31:01
【问题描述】:

我希望如果foo 在类D 中声明,但没有标记为虚拟,那么下面的代码将调用D 中的foo 的实现(不管d 的动态类型如何) )。

D& d = ...;
d.foo();

但是,在下面的程序中,情况并非如此。谁能解释一下?如果方法覆盖了虚函数,它会自动为虚函数吗?

#include <iostream>

using namespace std;

class C {
public:
        virtual void foo() { cout << "C" << endl; }
};

class D : public C {
public:
        void foo() { cout << "D" << endl; }
};

class E : public D {
public:
        void foo() { cout << "E" << endl; }
};

int main(int argc, char **argv)
{
        E& e = *new E;
        D& d = *static_cast<D*>(&e);
        d.foo();
        return 0;
}

上述程序的输出为:

E

【问题讨论】:

  • static_cast 是多余的 - 由于从 E*/E& 到 D*/D& 的隐式转换,D&amp; d = *static_cast&lt;D*&gt;(&amp;e); 等同于 D&amp; d = e;
  • 在 c++ 11 中,在函数声明中添加“覆盖”可以清楚地表明您打算覆盖基类函数。如果您声明的函数的 constness 与 base 不同,它还会触发编译器的错误(如果您从 std::exception 派生并声明 what() non-const,这可能会让您感到惊讶)

标签: c++ virtual overriding


【解决方案1】:

标准 10.3.2 (class.virtual) 说:

如果在Base类和Derived类中声明了一个虚成员函数vf,直接或间接从Base派生,则声明一个与Base::vf同名同参数列表的成员函数vf,则Derived ::vf 也是虚拟的(无论是否如此声明)并且它会覆盖*

[脚注:与虚函数同名但参数列表不同(子句)的函数不一定是虚函数,也不会覆盖。在覆盖函数的声明中使用 virtual 说明符是合法的但多余的(具有空语义)。在确定覆盖时不考虑访问控制(子句 class.access)。 --- 结束脚注]

【讨论】:

    【解决方案2】:

    快速回答可能是否定的,但正确答案是

    C++ 不知道函数隐藏,因此在没有 virtual 关键字的情况下覆盖虚拟函数也将函数标记为虚拟。

    【讨论】:

    • @Yossarian,这就是为什么在派生类中将虚函数声明为虚函数被认为是一种很好的做法,这样意图就很清楚了。 Scott Meyers 在他的 Effective C++ 书中讨论了这一点。
    • 我在某处听说过在派生方法中不标记 virtual 会使它们实际上是最终的。这使得第三级导数成为非虚拟覆盖。但我发现 Tadeusz 的标准摘录证明了这种信念是错误的,因为 indirectly 这个词,不是吗?
    • @v.oddou “我在某处听说过”人们“在某处听说过”的事情通常是错误的。 ;-) 只要有一个具有相同签名的函数标记为virtual somewhere 在层次结构中更高,那么任何具有相同签名的派生函数都是一个覆盖。声明是否包含 virtual 的“差距”不相关,同样,关键字在其最基本的外观之后具有空语义。
    【解决方案3】:

    您没有创建 e 对象的任何副本并将其放入 d 中。所以 d.foo() 遵循正常的多态行为并调用派生类方法。在基类中声明为虚拟的方法在派生类中也会自动变为虚拟。

    【讨论】:

      【解决方案4】:

      输出(“E”)的行为与预期的完全一样。

      原因: 该引用的动态(即运行时)类型是 E。您正在对 D 进行静态向上转换,但这当然不会改变对象的实际类型。

      这正是虚拟方法和动态调度背后的理念:您可以看到您正在实例化的类型的行为,在本例中为 E。

      【讨论】:

        最近更新 更多