为什么我们需要 C 中的虚函数?

新手上路,请多包涵

我正在学习 C++,我刚刚进入虚拟函数。

从我读到的(在书中和在线)中,虚函数是基类中的函数,您可以在派生类中覆盖它们。

但是在本书的前面,在学习基本继承时,我能够在不使用 virtual 的情况下覆盖派生类中的基函数。

那么我在这里错过了什么?我知道虚函数还有更多,而且它似乎很重要,所以我想弄清楚它到底是什么。我只是无法在网上找到一个简单的答案。

原文由 Jake Wilson 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 499
2 个回答

没有“虚拟”,您将获得“早期绑定”。使用该方法的哪个实现在编译时根据您调用的指针的类型来决定。

使用“虚拟”,您将获得“后期绑定”。使用该方法的哪个实现在运行时根据所指向对象的类型来决定——它最初被构造为什么。根据指向该对象的指针的类型,这不一定是您所想的。

 class Base
{
  public:
            void Method1 ()  {  std::cout << "Base::Method1" << std::endl;  }
    virtual void Method2 ()  {  std::cout << "Base::Method2" << std::endl;  }
};

class Derived : public Base
{
  public:
    void Method1 ()  {  std::cout << "Derived::Method1" << std::endl;  }
    void Method2 ()  {  std::cout << "Derived::Method2" << std::endl;  }
};

Base* basePtr = new Derived ();
  //  Note - constructed as Derived, but pointer stored as Base*

basePtr->Method1 ();  //  Prints "Base::Method1"
basePtr->Method2 ();  //  Prints "Derived::Method2"

编辑- 看到 这个问题

此外 - 本教程 涵盖 C++ 中的早期和后期绑定。

原文由 user180247 发布,翻译遵循 CC BY-SA 4.0 许可协议

跟进@user6359267 的回答,C++ 范围层次结构是

global -> namespace -> class -> local -> statement

因此,每个类都定义了一个范围。如果不是这种情况,子类中的重写函数实际上将重新定义同一范围内的函数,这是链接器不允许的:

  1. 在每个翻译单元中使用之前必须声明一个函数,并且
  2. 一个函数只能在整个程序的给定范围内定义一次(跨所有翻译单元)

由于每个类都定义了自己的范围,因此被调用的函数是在调用该函数的对象的类中定义的函数。所以,

 #include <iostream>
#include <string>

class Parent
{
public:
    std::string GetName() { return "Parent"; }
};

class Child : public Parent
{
public:
    std:::string GetName() { return "Child"; }
};

int main()
{
    Parent* parent = new Parent();
    std::cout << parent->GetName() << std::endl;

    Child* child = new Child();
    std::cout << child->GetName() << std::endl;

    *parent = child;
    std::cout << child->GetName() << std::endl;

    return 0;
}

输出

Parent
Child
Parent

因此,我们需要一种方法来告诉编译器要调用的函数应该在运行时而不是编译时确定。这就是 virtual 关键字的作用。

这就是为什么函数重载被称为编译时多态性(或早期绑定)而虚函数覆盖被称为运行时多态性(或后期绑定)的原因。

细节:

在内部,当编译器看到一个虚函数时,它会创建一个类成员指针,该指针通常使用 .* 指向类的成员(而不是对象中该成员的特定实例)和 ->* 运营商。他们的工作是允许您访问给定指向该成员的指针的类的成员。这些很少被程序员直接使用(也许除非你正在编写一个编译器来实现“虚拟”)。

原文由 A. Hendry 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题