协慌网

登录 贡献 社区

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

我正在学习 C ++ 而我正在进入虚拟功能。

根据我的阅读(在书中和在线),虚函数是基类中的函数,您可以在派生类中重写它们。

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

那我在这里错过了什么?我知道虚拟功能还有更多功能,而且它似乎很重要,所以我想清楚它究竟是什么。我在网上找不到直接答案。

答案

以下是我不仅了解virtual功能的原因,而且了解为什么需要它们:

假设你有这两个类:

class Animal
{
    public:
        void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

在你的主要功能:

Animal *animal = new Animal;
Cat *cat = new Cat;

animal->eat(); // Outputs: "I'm eating generic food."
cat->eat();    // Outputs: "I'm eating a rat."

到目前为止一切都那么好吧?动物吃普通食物,猫吃老鼠,都没有virtual

让我们稍微改变它,以便通过中间函数调用eat() (这个例子只是一个简单的函数):

// This can go at the top of the main.cpp file
void func(Animal *xyz) { xyz->eat(); }

现在我们的主要功能是:

Animal *animal = new Animal;
Cat *cat = new Cat;

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating generic food."

哦...... 我们把猫送进了func() ,但它不会吃老鼠。你应该重载func()所以它需要Cat*吗?如果你必须从 Animal 获得更多的动物,他们都需要自己的func()

解决方案是使Animal类中的eat()成为一个虚函数:

class Animal
{
    public:
        virtual void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

主要:

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating a rat."

完成。

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

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

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* obj = new Derived ();
  //  Note - constructed as Derived, but pointer stored as Base*

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

编辑 - 看到这个问题

此外 - 本教程还介绍了 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

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