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

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

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

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


当前回答

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

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

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

所以当你说:

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

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

其他回答

我想添加虚拟函数的另一种用法,尽管它使用了与上述答案相同的概念,但我认为它值得一提。

虚拟析构函数

考虑下面的这个程序,不要将基类析构函数声明为virtual;Cat的内存可能无法清理。

class Animal {
    public:
    ~Animal() {
        cout << "Deleting an Animal" << endl;
    }
};
class Cat:public Animal {
    public:
    ~Cat() {
        cout << "Deleting an Animal name Cat" << endl;
    }
};

int main() {
    Animal *a = new Cat();
    delete a;
    return 0;
}

输出:

删除动物

class Animal {
    public:
    virtual ~Animal() {
        cout << "Deleting an Animal" << endl;
    }
};
class Cat:public Animal {
    public:
    ~Cat(){
        cout << "Deleting an Animal name Cat" << endl;
    }
};

int main() {
    Animal *a = new Cat();
    delete a;
    return 0;
}

输出:

删除动物名称猫删除动物

您需要至少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
}

我认为您所指的是这样一个事实:一旦方法被声明为virtual,您就不需要在重写中使用“virtual”关键字。

class Base { virtual void foo(); };

class Derived : Base 
{ 
  void foo(); // this is overriding Base::foo
};

如果在Base的foo声明中不使用“virtual”,那么Derived的foo将只是隐藏它。

解释了虚拟功能的需求[易于理解]

#include<iostream>

using namespace std;

class A{
public: 
        void show(){
        cout << " Hello from Class A";
    }
};

class B :public A{
public:
     void show(){
        cout << " Hello from Class B";
    }
};


int main(){

    A *a1 = new B; // Create a base class pointer and assign address of derived object.
    a1->show();

}

输出将为:

Hello from Class A.

但具有虚拟功能:

#include<iostream>

using namespace std;

class A{
public:
    virtual void show(){
        cout << " Hello from Class A";
    }
};

class B :public A{
public:
    virtual void show(){
        cout << " Hello from Class B";
    }
};


int main(){

    A *a1 = new B;
    a1->show();

}

输出将为:

Hello from Class B.

因此,使用虚拟函数可以实现运行时多态性。

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

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

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