为什么虚函数优于派生 class 对象?

Why are virtual functions preferable over derived class objects?

所以我刚开始学习虚函数,我正在学习在线教程,但我似乎找不到问题的答案。我想问一下为什么通过将基础 class 对象设置为指向派生 class 对象来使用下面的虚函数比仅使用派生 class 对象本身来访问函数更可取?

似乎我得到了相同的输出,而且创建基础 class 对象和虚函数似乎是额外的步骤。我在一个在线教程中看到了一个与此类似的示例,该教程声称虚函数使编码更容易,但我不太清楚这个示例的好处?

我在网上看到:

The main advantage of virtual functions are that they directly support object oriented programming. When you declare a function as virtual you're saying that exactly what code is executed depends on the type of the object you call it against.

但使用派生对象似乎已经是这种情况,并且创建基础 class 对象是不必要的?我确定我遗漏了一些明显的东西,所以我非常感谢任何帮助。我在下面展示了我编写的示例代码,它与我在详细介绍虚函数时看到的代码类似:

#include <iostream>

using namespace std;

//////////////////////////////////////////////////////
//base class
class Shape {

public:
virtual void draw()=0;  //pure virtual function
};

//derived classes
class Square : public Shape {

public:
void draw() {
    cout << "Draw square" << endl;
    }

};

class Circle : public Shape {

public:
void draw() {
    cout << "Draw circle " << endl;
    }

};

//////////////////////////////////////////////////////
int main()
{
Square so;  //create derived class objects
Circle co;

Shape* shape1 = &so;  //setting base class objects as pointers to derived objects
Shape* shape2 = &co;


shape1->draw();  //using base class objects to access derived class
shape2->draw();

so.draw();  //using derived class objects
co.draw();

}

使用基本 class 指针类型和虚函数的巨大好处是您可以拥有一个包含多种不同类型 Shape 的列表,并且您可以处理它们在单个函数中,由于派生类型不同,它们都将具有不同的行为。

例如,我修改了您的代码,添加了接受 vector<Shapes*>& 的函数 DrawAllShapes。 (小心使用原始指针。你真的应该在这里使用 vector<std::unique_ptr<Shape>>& 或类似的东西。

这种模式具有令人难以置信的灵活性,它允许您在基础 class 指针对象的集合上调用相同的函数,但会根据其派生类型为集合中的每个对象产生不同的行为。

#include <iostream>
#include <vector>
using namespace std;

//////////////////////////////////////////////////////
//base class
class Shape {

public:
    virtual void draw() = 0;  //pure virtual function
};

//derived classes
class Square : public Shape {

public:
    void draw() {
        cout << "Draw square" << endl;
    }

};

class Circle : public Shape {

public:
    void draw() {
        cout << "Draw circle " << endl;
    }

};

void DrawAllShapes(std::vector<Shape*>& shapes) {
    for (int i = 0; i < shapes.size(); ++i) {
        shapes[i]->draw();
    }
}

//////////////////////////////////////////////////////
int main()
{
    std::vector<Shape*> shapeVec{ new Square, new Circle, new Square, new Square, new Circle };
    DrawAllShapes(shapeVec);

    system("pause");
}

另外,想象一下如果您使用的是一个预建的图形库,它已经定义了一个形状 class 和多个形状。如果您想添加自己的新型 Shape 并使其与库的所有函数完美配合怎么办?您所要做的就是创建您自己的派生 class 并实现库的 Shape class 公开的所有必要虚函数,然后您实际上已经扩展了库的原始功能。