Почему виртуальные функции предпочтительнее объектов производного класса? - PullRequest
0 голосов
/ 10 марта 2020

Итак, я новичок в изучении виртуальных функций и слежу за онлайн-уроками, и я не могу найти ответ на свой вопрос. Я хочу спросить, почему использование виртуальных функций, указанных ниже, путем установки объектов базового класса для указания на объекты производного класса, предпочтительнее, чем просто использование самих объектов производного класса для доступа к функциям?

Кажется, что я получаю один и тот же вывод, и кажется, что создание объектов базового класса и виртуальных функций - дополнительные шаги. Я видел пример, подобный этому, в онлайн-учебнике, в котором утверждалось, что виртуальные функции упрощают кодирование, но я не совсем вижу преимущества в этом примере?

Я читал в Интернете, что:

Основным преимуществом виртуальных функций является то, что они напрямую поддерживают объектно-ориентированное программирование. Когда вы объявляете функцию виртуальной, вы говорите, что то, какой именно код выполняется, зависит от типа объекта, для которого вы ее вызываете.

Но, похоже, это уже имеет место при использовании производных объектов, а что создавать объекты базового класса не нужно? Я уверен, что упускаю что-то очевидное, поэтому я был бы очень признателен за любую помощь. Я показал пример кода, который я написал ниже, который похож на то, что я видел при детализации виртуальных функций:

#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();

}

1 Ответ

0 голосов
/ 10 марта 2020

Огромное преимущество, которое вы получаете за использование типа указателя базового класса и виртуальных функций, состоит в том, что вы можете иметь один единственный список, содержащий несколько различных типов 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");
}

Кроме того, представьте, что вы используете предварительно собранную графическую библиотеку, в которой уже есть класс Shape и определены несколько фигур. Что если вы Вы хотели добавить свой собственный новый тип Shape, и он прекрасно работал со всеми функциями библиотеки? Все, что вам нужно было бы сделать, это создать собственный производный класс и реализовать все необходимые виртуальные функции, предоставляемые классом Shape библиотеки, а затем буквально расширил библиотеку за пределы ее первоначальных возможностей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...