Абстрактные базовые классы

Базовый класс иерархии типа обычно содержит ряд виртуальных функций, которые обеспечивают динамическую типизацию. Часто в базовом классе эти виртуальные функции фиктивны и имеют пустое тело. Определенное значение им придают в порожденных классах. В С++ для этой цели применяется чистая виртуальная функция. Чистая виртуальная функция - виртуальная функция-член, тело которой обычно не определено. Запись этого объявления внутри класса следующая:

virtual прототип функции = 0;

Чистая виртуальная функция используется для того, чтобы “отложить” решение о реализации функции. В ООП терминологии это называется отсроченным методом.

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

Объясним эту концепцию при помощи разработки примитивной формы экологического моделирования. В нашем примере будем иметь различные формы взаимодействия жизни с использованием абстрактного базового класса living. Создадим fox (лису) как типичного хищника, и rabbit (кролика) как его жертву. Rabbit есть grass (траву).

const int N = 40, STATES=4; // размер квадратной площади

enum state { EMPTY, GRASS, RABBIT, FOX };

class living;

typedef living *world[N][N]; // world будет моделью

class living { // что живет в мире

protected:

int row, column; // местоположение

void sums(world, int sm[]); // sm[#states] используется next

public:

living(int r,int c):row(r),column(c) {}

virtual state who()=0; // идентификация состояний

virtual living* next(world w)=0; // расчет next

};

void living::sums(world w,int sm[]) {

sm[EMPTY]=sm[GRASS]=sm[RABBIT]=sm[FOX]=0;

for(int i=-1; i <= 1; i++)

for(int j=-1; j <= 1; j++) sm[w[row+i][column+j]->who()]++;

}

// текущий класс - только хищники

class fox: public living {

protected:

int age; // используется для принятия решения о смерти

public:

fox(int r,int c,int a=0):living(r,c),age(a) {}

state who() { return FOX; } // отложенный метод для FOX

living* next(world w); // отложенный метод для FOX

};

// текущий класс - только жертвы

class rabbit: public living {

protected:

int age; // используется для принятия решения о смерти

public:

rabbit(int r,int c,int a=0):living(r,c),age(a) {}

state who() { return RABBIT; } // отложенный метод для RABBIT

living* next(world w); // отложенный метод для RABBIT

};

// текущий класс - только растения

class grass: public living {

public:

grass(int r,int c):living(r,c) {}

state who() { return GRASS; } // отложенный метод для GRASS

living* next(world w); // отложенный метод для GRASS

};

// жизнь отсутствует

class empty: public living {

public:

empty(int r,int c):living(r,c) {}

state who() { return EMPTY; } // отложенный метод для EMPTY

living* next(world w); // отложенный метод для EMPTY

};

Обратите внимание на то, что проект позволяет развивать и другие формы хищника, жертвы и растительной жизни, используя следующий уровень наследования. Характеристики поведения каждой формы жизни фиксируется в версии next().

Living* grass::next(world w) {

int sum[STATES];

sums(w,sum);

if(sum[GRASS] > sum[RABBIT) // есть траву

return (new grass(row,column));

else

return (new empty(row,column));

}

Grass может быть съеден Rabbit. Если в окрестности имеется больше grass, чем rabbit, grass остается, иначе - grass будет съедена.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: