Выбрать главу

#include <iostream>

using namespace std;

class figure {

 protected:

  double x, y;

 public:

  void set_dim(double i, double j=0) {

   x = i;

   у = j;

  }

  virtual void show_area() {

   cout << "Для этого класса выражение вычисления ";

   cout << "площади не определено.\n";

  }

};

class triangle : public figure {

 public:

  void show_area() {

   cout << "Треугольник с высотой ";

   cout << x << " и основанием " << у;

   cout << " имеет площадь ";

   cout << х * 0.5 * у << ".\n";

  }

};

class rectangle : public figure {

 public:

  void show_area() {

   cout << "Прямоугольник с размерами ";

   cout << x << " x " << у;

   cout << " имеет площадь ";

   cout << х * у << ".\n";

  }

};

class circle : public figure {

 public:

  void show_area() {

   cout << "Круг с радиусом ";

   cout << x;

   cout << " имеет площадь ";

   cout << 3.14 * x * x << ".\n";

  }

};

int main()

{

 figure *p; // создаем указатель на базовый тип

 triangle t; // создаем объекты производных типов

 rectangle r;

 circle с;

 р = &t;

 p->set_dim(10.0, 5.0);

 p->show_area();

 р = &r;

 p->set_dim(10.0, 5.0);

 p->show_area();

 р = &с;

 p->set_dim(9.0);

 p->show_area();

 return 0;

}

При выполнении эта программа генерирует такие результаты.

Треугольник с высотой 10 и основанием 5 имеет площадь 25.

Прямоугольник с размерами 10 х 5 имеет площадь 50.

Круг с радиусом 9 имеет площадь 254.34.

Важно! Несмотря на то что виртуальные функции синтаксически просты для понимания, их настоящую силу невозможно продемонстрировать на коротких примерах. Как правило, могущество полиморфизма проявляется в больших сложных системах. По мере освоения C++ вам еще не раз представится случай убедиться в их полезности.

Чисто виртуальные функции и абстрактные классы

Как вы могли убедиться, если виртуальная функция, которая не переопределена в производном классе, вызывается объектом этого производного класса, то используется версия, определенная в базовом классе. Но во многих случаях вообще нет смысла давать определение виртуальной функции в базовом классе. Например, в базовом классе figure (из предыдущего примера) определение функции show_area() — это просто заглушка. Она не вычисляет и не отображает площадь ни одного из объектов. Как вы увидите при создании собственных библиотек классов, в том, что виртуальная функция не имеет значащего определения в контексте базового класса, нет ничего необычного.

Чисто виртуальная функция — это виртуальная функция, которая не имеет определения в базовом классе.

Существует два способа обработки таких ситуаций. Первый (он показан в предыдущем примере программы) заключается в обеспечении функцией вывода предупреждающего сообщения. Возможно, такой подход и будет полезен в определенных ситуациях, но в большинстве случаев он попросту неприемлем. Например, можно представить себе виртуальные функции, без определения которых в существовании производного класса вообще нет никакого смысла. Рассмотрим класс triangle. Он абсолютно бесполезен, если в нем не определить функцию show_area(). В этом случае имеет смысл создать метод, который бы гарантировал, что производный класс действительно содержит все необходимые функции. В C++ для решения этой проблемы и предусмотрены чисто виртуальные функции.