我正在学习C++,我刚刚开始学习虚拟函数。

从我(在书中和网上)读到的内容来看,虚拟函数是基类中的函数,可以在派生类中重写。

但在本书的早些时候,当我学习基本继承时,我能够在派生类中重写基函数,而不使用虚函数。

那么我在这里错过了什么?我知道虚拟函数还有很多,它似乎很重要,所以我想清楚它到底是什么。我只是在网上找不到一个直截了当的答案。


当前回答

虚拟函数用于支持运行时多态性。

也就是说,virtual关键字告诉编译器不要在编译时做出(函数绑定的)决定,而是推迟到运行时”。

您可以通过在函数的基类声明中的关键字virtual之前使其成为虚拟函数。例如类基础{虚虚函数();}当基类具有虚拟成员函数时,从基类继承的任何类都可以使用完全相同的原型重新定义该函数,即只能重新定义功能,而不能重新定义函数的接口。类派生:公共基{void函数();}基类指针可用于指向基类对象和派生类对象。当使用基类指针调用虚拟函数时,编译器在运行时决定要调用函数的哪个版本(即基类版本或重写的派生类版本)。这被称为运行时多态性。

其他回答

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

使用“虚拟”,您将获得“后期绑定”。使用方法的哪种实现在运行时根据指向对象的类型来决定,即它最初的构造形式。这不一定是根据指向该对象的指针的类型来考虑的。

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++中的早期和后期绑定。

当基类中有函数时,可以在派生类中重新定义或重写它。

重新定义方法:派生类中给出了基类方法的新实现。不便于动态绑定。

重写方法:在派生类中重新定义基类的虚拟方法。虚拟方法有助于动态绑定。

所以当你说:

但在书的早些时候,当我了解基本遗传时能够重写派生类中的基方法,而不使用“虚拟”。

因为基类中的方法不是虚拟的,所以您不是在重写它,而是在重新定义它

关于效率,虚拟函数的效率略低于早期绑定函数。

“这种虚拟调用机制的效率几乎可以与“正常函数调用”机制一样高(25%以内)。它的空间开销是一个具有虚拟函数的类的每个对象中的一个指针加上每个此类类的一个vtbl”[Bjarne Stroustrup的C++教程]

您需要至少1个级别的继承和一个升级来演示它。下面是一个非常简单的示例:

class Animal
{        
    public: 
      // turn the following virtual modifier on/off to see what happens
      //virtual   
      std::string Says() { return "?"; }  
};

class Dog: public Animal
{
    public: std::string Says() { return "Woof"; }
};

void test()
{
    Dog* d = new Dog();
    Animal* a = d;       // refer to Dog instance with Animal pointer

    std::cout << d->Says();   // always Woof
    std::cout << a->Says();   // Woof or ?, depends on virtual
}

为什么我们需要C++中的虚拟方法?

快速回答:

它为我们提供了面向对象编程所需的“要素”之一。

在Bjarne Stroustrup C++编程:原理与实践中,(14.3):

虚拟函数提供了在基类中定义函数的能力,并在用户调用基类函数时在派生类中具有相同名称和类型的函数。这通常称为运行时多态性、动态调度或运行时调度,因为调用的函数是在运行时根据所使用的对象类型确定的。

如果您需要虚拟函数调用2,这是最快、更有效的实现。

为了处理虚拟调用,需要一条或多条与派生对象3相关的数据。通常的做法是添加函数表的地址。该表通常称为虚拟表或虚拟函数表,其地址通常称为虚指针。每个虚拟函数在虚拟表中都有一个槽。根据调用者的对象(派生)类型,虚拟函数依次调用相应的重写。


1.使用继承、运行时多态性和封装是面向对象编程的最常见定义。

2.您不能在运行时使用其他语言功能在备选方案中进行选择,从而使功能更快或使用更少的内存。Bjarne Stroustrup C++编程:原理与实践。(14.3.1).

3.当我们调用包含虚拟函数的基类时,可以判断哪个函数真正被调用。