因此,我刚开始学习虚函数,并且正在关注在线教程,但似乎找不到我的问题的答案。我想问一个问题,为什么在下面通过将基类对象设置为指向派生类对象来使用虚函数,而不是仅使用派生类对象本身来访问函数呢?
似乎无论哪种方式我都得到相同的输出,并且似乎创建基类对象和虚函数是额外的步骤。我在在线教程中看到了与此类似的示例,该示例声称虚拟函数使编码更容易,但我不太明白此示例的好处吗?
我在线阅读:
虚拟函数的主要优点是它们直接支持面向对象的编程。当您将一个函数声明为虚函数时,您要说的是确切执行什么代码取决于调用它的对象的类型。
但是似乎已经使用派生对象了,创建基类对象是不必要的吗?我确信我缺少明显的东西,因此我将非常感谢您的帮助。我展示了下面编写的示例代码,该代码类似于详细介绍虚函数时看到的代码:
#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();
}
使用基类指针类型和虚函数所获得的巨大好处是,您可以拥有一个包含几种不同类型的Shape
的单个列表,并且可以在单个函数中将它们全部处理,由于它们的派生类型而有不同的行为。
作为示例,我通过添加包含DrawAllShapes
的函数vector<Shapes*>&
修改了您的代码。 (请小心使用原始指针。您确实应该在此处使用vector<std::unique_ptr<Shape>>&
或类似的名称。
这种模式具有极大的灵活性,它使您可以在基类指针对象的集合上调用相同的函数,但是根据其派生类型,集合中的每个对象都会导致不同的行为。
#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");
}