当前位置: 首页 > 知识库问答 >
问题:

重写非虚拟方法

卢英叡
2023-03-14

让我们在Visual C 2010中假设以下场景:

#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;
};

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

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

因为基类的显示方法不是虚拟方法,所以派生类不能重写它。正当

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

    < li >基本:非虚拟显示。 < li >基本:虚拟显示。 < li >派生:非虚拟显示。 < li >派生:虚拟显示。

所以,要么我不理解虚拟方法的概念,要么在Visual C中发生了一些奇怪的事情。

有人能帮我解释一下吗?

共有3个答案

魏宏邈
2023-03-14

我认为在静态与动态绑定的背景下看待它可能会更好。

如果该方法是非虚拟的(与Java不同,它在C中已经是默认的),则该方法在编译时绑定到它的调用方,这不可能知道运行时将指向的实际对象。因此,变量类型才是最重要的,它是“基础”。

柯升
2023-03-14

是的,你有点误解了:

纯虚函数:

< code > virtual void fun 1()= 0 -

虚拟功能:

虚拟void fun2()-

正常功能:

< code>void fun3() -

为了实现运行时多态性,您需要覆盖c中的虚拟函数

凌轶
2023-03-14

是的,你有点误解了。

在这种情况下,派生类上同名的方法将隐藏父方法。您可以想象,如果不是这样,尝试创建与基类非虚方法同名的方法应该会抛出错误。这是允许的,也不是问题——如果您像这样直接调用该方法,它将被调用。

但是,由于C方法不是虚拟的,所以不会使用允许多态性的C方法查找机制。例如,如果你创建了一个派生类的实例,但是通过一个指向基类的指针调用了你的“Display”方法,那么基类的方法将被调用,而对于“vDisplay ”,派生类的方法将被调用。

例如,尝试添加以下行:

Base *b = &ba;
b->Display();
b->vDisplay();
b = &de;
b->Display();
b->vDisplay();

...并按预期观察输出:

基本:非虚拟显示。< br >基本:虚拟显示。基本:非虚拟显示。
派生:虚拟显示。< br >

 类似资料:
  • 我对虚拟函数感到困惑。有人告诉我,父类中的虚拟意味着我可以在子类中覆盖它。但是,如果我省略父类中的虚拟,我仍然可以覆盖它。

  • 我是C#新手,我不明白编译器为什么不抱怨这段代码。以下是类的层次结构: 执行代码: 执行时<代码>---- 当决定调用什么函数时--运行时还是编译时?如果我弄脏了一个新的< code>class CAble : IAble怎么办?

  • 我在2009年9月28日提交了以下bug。遗憾的是,我仍然没有得到任何回应,规范的最终版本仍然不正确。这真的是一个bug吗?如果不是,为什么不呢?如果是,我该怎么办? 包含错误的部分是(方法重写):http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.4.5结合opcode的描述:http://docs.oracl

  • 问题内容: 在继承中虚拟函数如何在后台工作?编译器是否特别对待虚拟函数? 问题答案: 是的,编译器和运行时对虚拟方法的处理方式有所不同。JVM专门利用虚拟方法表进行虚拟方法分配: 对象的调度表将包含对象的动态绑定方法的地址。通过从对象的分派表中获取方法的地址来执行方法调用。属于同一类的所有对象的分发表都是相同的,因此通常在它们之间共享。属于类型兼容类的对象(例如,继承层次结构中的同级对象)将具有具

  • 每个人都知道基类的分解器通常必须是虚拟的。但是派生类的析构函数是什么?在 C 11 中,我们有关键字“override”,并且能够显式使用默认析构函数。 在子类的析构函数中同时使用关键字“覆盖”和“=默认”是否正确?在这种情况下,编译器会生成正确的虚拟析构函数吗? 如果是,那么我们是否可以认为这是好的编码风格,我们应该总是这样声明派生类的析构函数,以确保基类析构函数是虚的?

  • 不能将“virtualenv”识别为内部或外部命令、可操作程序或批处理文件。 我正在遵循的步骤 在默认目录下安装-pip安装virtualenv 要创建一个venv,请运行此virtualenv-p python3 venv 激活virtualenv\Scripts\Activate 它看起来像这样(venv)