22

我希望如果foo在 class 中声明D,但未标记为 virtual,则以下代码将调用fooin的实现D(无论 的动态类型如何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
4

4 回答 4

24

标准 10.3.2 (class.virtual) 说:

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

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

于 2009-09-10T11:53:54.920 回答
17

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

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

于 2009-09-10T11:46:32.690 回答
0

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

于 2009-09-10T11:48:08.600 回答
-1

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

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

这就是虚方法和动态调度背后的想法:您可以看到您正在实例化的类型的行为,在这种情况下是 E。

于 2009-09-10T11:51:34.003 回答