关于C++:重写非虚方法

Overriding non-virtual methods

让我们假设Visual C++ 2010中的这个场景:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <conio.h>

using namespace std;

class Base
{
public:
    int b;
    void Display()
    {
        cout<<"Base: Non-virtual display."<<endl;
    };
    virtual void vDisplay()
    {
        cout<<"Base: Virtual display."<<endl;
    };
};

class Derived : public Base
{
public:
    int d;
    void Display()
    {
        cout<<"Derived: Non-virtual display."<<endl;
    };
    virtual void vDisplay()
    {
        cout<<"Derived: Virtual display."<<endl;
    };
};

int main()
{
    Base ba;
    Derived de;

    ba.Display();
    ba.vDisplay();
    de.Display();
    de.vDisplay();

    _getch();
    return 0;
};

理论上,这个小应用程序的输出应该是:

  • 基本:非虚拟显示。
  • 基础:虚拟显示。
  • 基本:非虚拟显示。
  • 派生:虚拟显示。

因为基类的显示方法不是虚拟方法,所以派生类不应该重写它。对吗?

问题是,当我运行应用程序时,它会打印以下内容:

  • 基本:非虚拟显示。
  • 基础:虚拟显示。
  • 派生:非虚拟显示。
  • 派生:虚拟显示。

所以我不理解虚拟方法的概念或者在VisualC++中发生了一些奇怪的事情。

有人能帮我解释一下吗?


是的,你有点误会。

在这种情况下,派生类上同名的方法将隐藏父方法。如果不是这样,尝试创建一个与基类同名的非虚拟方法会引发错误。它是允许的,这不是问题——如果像您所做的那样直接调用该方法,它将被称为fine。

但是,作为非虚的,不允许使用多态性的C++方法查找机制。因此,例如,如果创建了派生类的实例,但通过指向基类的指针调用了"display"方法,则将调用基的方法,而对于"vdisplay",则将调用派生方法。

例如,尝试添加这些行:

1
2
3
4
5
6
Base *b = &ba;
b->Display();
b->vDisplay();
b = &de;
b->Display();
b->vDisplay();

…并按预期观察输出:

Base: Non-virtual display.
Base: Virtual display.
Base: Non-virtual display.
Derived: Virtual display.

< /块引用>


是的,你有点误解了:

纯虚拟函数:

virtual void fun1()=0->必须在派生类中重写

虚拟功能:

可以覆盖virtual void fun2()->

正常功能:

void fun3()->不要覆盖它

为了实现运行时多态性,需要在C++中重写虚拟函数。


我认为在静态绑定和动态绑定的上下文中查看它可能更好。

如果该方法是非虚的(它已经默认在C++中不同于Java),那么该方法在编译时绑定到它的调用方,这是不可能知道将在运行时指向的实际对象的。所以,变量类型是所有重要的"基础"。