Чистая виртуальная функция — это функция, объявленная в базовом классе и не имеющая в этом классе своего определения. В этом случае каждый производный класс должен обязательно определить собственный вариант функции — он не может использовать функцию, которая не имеет определения. Для объявления чистой виртуaльной функции используется такая общая форма:
virtual тип имя-функции(список-параметров) = 0;
Здесь тип представляет собой тип возвращаемого функцией значения, а имя-функции — ее имя.
Используя чистые виртуальные функции, вы можете улучшить TwoDShape. Поскольку для неопределенной двумерной фигуры нельзя предложить разумный способ вычисления площади, в приведенном варианте предыдущей программы функция агеа() объявлена внутри класса TwoDShape как чистая виртуальная. Это, разумеется, означает, что все классы, производные от TwoDShape, должны переопределять агеа().
// Использование чистой виртуальной функции.
#include <iostream>
#include <cstring>
#include <conio>
using namespace std;
// Класс для двумерных объектов.
class TwoDShape {
// эти члены закрыты
double width;
double height;
// добавим поле для названия фигуры
char name[20];
public :
// Конструктор по умолчанию.
TwoDShape() {
width = height = 0.0;
strcpy(name, "неизвестно");
}
// Конструктор для TwoDShape.
TwoDShape(double w, double h, char *n) {
width = w;
height = h;
strcpy(name, n);
}
// Конструируем объект с равными шириной и высотой.
TwoDShape (double x, char *n) {
width = height = x;
strcpy(name, n);
}
void showDim() {
cout << "Ширина и высота составляют "
<< width << " и " << height << "\n";
}
// функции доступа
double getWidth() { return width; }
double getHeight() { return height; }
void setWidth (double w) { width = w; }
void setHeight (double h) { height = h; }
char *getName() { return name; }
// area() теперь чистая виртуальная функция
virtual double area ()= 0;
};
// Triangle является производным от TwoDShape.
class Triangle : public TwoDShape {
char style[20]; // теперь private
public:
/* Конструктор по умолчанию. Он автоматически вызывает
for(int i=0; i < 4; i++) { // Теперь для каждого объекта вызываем
//правильный вариант функции агеа()
cout << "объект представляет собой " <<
shapes[i]->getName() << "\n";
cout << "Площадь равна " <<
shapes[i]->area() << "\n";
cout << "\n";
}
getch();
return 0;
}
Если класс имеет хотя бы одну чистую виртуальную функцию, про него говорят, что это абстрактный класс. Абстрактный класс имеет одну важную черту: нельзя создать объект такого класса. Чтобы убедиться в справедливости этого утверждения, попробуйте удалить переопределение агеа( ) из класса Triangle последней программы. При попытке создать экземпляр Triangle вы получите сообщение об ошибке. Абстрактный класс может быть использован только в качестве базового, от которого будут наследовать другие классы. Причина невозможности объявить объект абстрактного класса заключается в том, что одна или несколько его функций не имеют определений. Именно поэтому массив shapes в последней программе уменьшен до четырех элементов и не создается обобщенный объект TwoDShape. Как это видно из программы, если базовый класс является абстрактным, вы, тем не менее, можете объявить указатель этого класса, который будет затем использоваться для указания на объекты производных классов.