Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lutsik_Yu_A_Obektno_orientir_programmir_na_yaz.pdf
Скачиваний:
63
Добавлен:
11.05.2015
Размер:
4.33 Mб
Скачать

невиртуальной. При этом также требуется дополнительная память для хранения виртуальной таблицы;

- при использовании полного имени при вызове некоторой виртуальной функции (например grup ::see();) виртуальный механизм не применяется.

4.3. Абстрактные классы

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

имеет вид

Р

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

Чисто виртуальная функция используется для тогоИ, чтобы отложить ре-

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

альную функцию, то он называется страктнымБ . Для абстрактного класса

нельзя создать объекты и он используется только как базовый класс для других

классов. Если base – абстрактный л сс, то для инструкций

base a;

 

 

 

аб

base *p= new base;

 

к

 

 

 

компилятор выдаст сообщ ние об ошибке. В то же время вполне можно исполь-

зовать инструкции вида

е

 

rect b;

т

 

 

base *p=&b;

 

 

base &p=b;

 

 

о

 

 

 

 

 

 

 

Чисто в ртуальную функцию, как и просто виртуальную функцию, необя-

зательно переопределятьли в производных классах. При этом если в производном классе она не переопределена, то этот класс тоже будет абстрактным, и при по- пытке создать объект этого класса компилятор выдаст ошибку. Таким образом,

забыть переопределить чисто виртуальную функцию невозможно. Абстрактный

 

б

базовый класс навязывает определенный интерфейс всем производным от него

классами. Главное назначение абстрактных классов в определении интерфейса

для некоторой иерархии классов.

Б

Класс можно сделать абстрактным, даже если все его функции определе-

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

class base

{компоненты-данные public:

85

virtual ~base() = 0;

компоненты-функции

}

base ::~base() {реализация деструктора}

Объект класса base создать невозможно, в то же время деструктор его оп- ределен и будет вызван при разрушении объектов производных классов.

Для иерархии типа полезно иметь базовый абстрактный класс. Он содер-

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

В примере мир будет иметь различные формы взаимодействия жизни с исполь-

зованием абстрактного базового класса living. Его интерфейс унаследованРраз-

 

 

 

 

 

 

У

личными формами жизни. Создадим fox (лис) – хищника, rabbit (кролик) –

жертву и grass – (траву).

 

 

 

Г

И

 

 

 

 

 

#include <iostream>

 

 

 

Б

 

 

using namespace std;

 

 

 

 

 

 

 

 

 

 

 

#include <conio.h>

 

 

 

 

 

 

// моделирование хищник − жертва с использованием

 

 

// иерархии классов

 

 

 

 

 

 

const int N=6,

 

 

// размер в др тной площади (мира)

STATES=4,

 

 

е

 

 

 

// колич ствоавидов жизни

 

 

DRAB=5,DFOX=5,

// колич кство циклов жизни кролика и лиса

CYCLES=10;

 

т

число циклов моделирования мира

 

// общ

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

 

 

class living;

 

о

// forvard объявление

 

 

 

и

 

// world − модель мира

 

 

typedef living *world[N][N];

 

 

 

void init(world);

 

 

 

 

 

 

 

л

 

 

 

 

 

 

void gener(world);

 

 

 

 

 

 

б

 

 

 

 

 

 

 

void update(world,world);

 

 

 

 

 

void dele(world);

 

 

 

 

 

 

 

class living

 

 

 

 

 

 

 

Б

 

 

 

 

 

 

 

{protected:

 

 

 

 

 

 

 

intиrow,col;

 

 

 

 

// местоположение в модели

void sums(world w,int sm[]);

 

//

 

 

public:

 

 

 

 

 

 

 

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

 

 

 

virtual state who() = 0;

 

 

// идентификация состояний

virtual living *next(world w)=0;

// расчет next

 

 

virtual void print()=0;

 

 

// вывод содержимого поля модели

};

 

 

 

 

 

 

 

86

 

 

 

 

 

 

 

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

{int i,j; sm[EMPTY]=sm[GRASS]=sm[RABBIT]=sm[FOX]=0; int i1=-1,i2=1,j1=-1,j2=1;

if(row==0)

i1=0;

 

// координаты внешних клеток модели

if(row==N-1) i2=0;

 

 

 

 

if(col==0)

j1=0;

 

 

 

 

if(col==N-1)

j2=0;

 

 

 

Р

}

 

 

 

 

for(i=i1;i<=i2;++i)

 

 

 

 

for(j=j1;j<=j2;++j)

 

 

И

sm[w[row+i][col+j]->who()]++;

 

У

 

В базовом классе living

 

 

объявлены две чисто виртуальные функции −

 

 

 

Г

 

 

who() и next() и одна обычная функция sums(). Моделирование имеет правила

для решения о том, кто продолжает жить в следующем цикле. Они основаны на

 

 

 

 

 

 

 

 

Б

соседствующих популяциях в некотором квадрате. лубина иерархии наследо-

вания один уровень.

 

 

а

 

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

 

 

class fox:public living

 

к

 

 

 

 

 

 

 

{ protected:

 

е

 

 

 

 

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

 

public:

 

 

 

 

 

 

 

 

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

 

 

 

 

о

 

 

 

// отложенный метод для foxes

 

 

state who() {return FOX;}

 

 

 

living *next(world w);

 

 

// отложенный метод для foxes

 

 

 

ий

 

 

 

 

 

};

void print(){coutт<< " ли ";}

 

 

 

л

 

 

 

 

 

 

 

 

 

 

 

 

 

 

б

 

 

 

 

 

 

 

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

 

 

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

 

};

void print(){cout << " кр ";}

 

 

 

 

 

 

 

 

 

 

// текущий класс - только растения class grass:public living

87

{ public:

 

 

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

 

 

state who() {return GRASS;}

// отложенный метод для grass

living *next(world w);

// отложенный метод для grass

void print(){cout << " тр ";}

 

 

};

 

 

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

 

 

class empty : public living

 

 

{ public:

 

 

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

 

И

};

 

state who() {return EMPTY;}

// отложенный метод для empty

living *next(world w);

// отложенный метод для emptyР

void print(){cout << " ";}

У

 

Г

 

Характеристика поведения каждой формы жизни фиксируется в версии next(). Если в окрестности имеется больше grass, чем rabbit, grass остается, ина-

че grass будет съедена.

 

 

 

 

 

а

living *grass::next(world w)

 

 

 

 

 

Б

{ int sum[STATES];

 

 

 

к

 

sums(w,sum);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

if(sum[GRASS]>sum[RABBIT])

 

 

// ролик ест траву

 

return (new grass(row,col));

 

 

 

 

 

 

else

 

 

ает

 

 

 

 

return(new empty(row,col));

 

е

 

 

}

 

 

го

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Если возраст rabbit превыш

определенное значение DRAB, он умирает,

 

 

 

и

 

 

 

 

 

 

либо, если поблизости мно л с, н может быть съеден.

living *rabbit::next(world w)

 

 

 

 

 

 

{ int sum[STATES];

 

 

 

 

 

 

 

 

б

 

 

 

 

 

 

 

 

sums(w,sum);

 

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

if(sum[FOX]>=sum[RABBIT])л

 

 

 

// лис ест кролика

 

return (new empty(row,col));

 

 

 

 

 

Б

 

 

 

 

 

 

// кролик слишком старый

 

else if(age>DRAB)

 

 

 

 

 

return(new empty(row,col));

 

 

 

 

else

 

 

 

 

 

 

 

 

}

return(new rabbit(row,col,age+1));

// кролик постарел

 

 

 

 

 

 

 

 

 

Fox тоже умирает от старости.

 

 

 

 

 

living *fox::next(world w)

 

 

 

 

 

 

{ int sum[STATES];

 

 

 

 

 

 

 

sums(w,sum);

 

 

 

 

 

 

 

 

if(sum[FOX]>5)

 

 

 

 

// слишком много лис

88

 

 

 

 

 

 

 

 

 

 

return (new empty(row,col));

 

 

 

 

 

 

else if(age>DFOX)

 

 

 

// лис слишком старый

 

return(new empty(row,col));

 

 

 

 

 

else

 

 

 

 

 

 

 

 

return(new fox(row,col,age+1));

// лис постарел

 

 

}

 

 

 

 

 

 

 

 

 

// заполнение пустой площади

 

 

 

 

 

 

living *empty::next(world w)

 

 

 

 

 

 

{ int sum[STATES];

 

 

 

 

 

 

 

 

sums(w,sum);

 

 

 

 

 

 

 

 

if(sum[FOX]>1)

 

 

 

// первыми добавляются лисы

 

return (new fox(row,col));

 

У

Р

 

else if(sum[RABBIT]>1)

 

 

// вторыми добавляются кролики

 

return (new rabbit(row,col));

Г

И

 

else if(sum[GRASS])

 

 

// третьими добавляются растения

 

 

return (new grass(row,col));

 

 

 

 

 

 

else return (new empty(row,col));// иначе пусто

 

 

}

 

 

 

а

 

 

 

 

Массив world представляет собой контейнерБ

для жизненных форм. Он

 

 

 

 

к

 

 

 

 

должен иметь в собственности объе ты living, чтобы распределять новые и уда-

лять старые.

 

 

 

 

 

 

 

 

 

// world полностью пуст

 

 

 

 

 

 

 

void init(world w)

е

 

 

 

 

 

 

{ int i,j;

о

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

for(i=0;i<N;++i)

 

 

 

 

 

 

 

 

for(j=0;j<N;++j)

 

 

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

w[i][j]=new empty(i,j);т

 

 

 

 

 

 

 

б

 

 

 

 

 

 

 

 

 

// генерация исходной модели мира

 

 

 

 

и

 

 

 

 

 

 

 

 

 

voidлgener(world w)

 

 

 

 

 

 

 

Б

{ int i,j;

 

 

 

 

 

 

 

 

for(i=0;i<N;++i)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

for(j=0;j<N;++j)

{ if(i%2==0 && j%3==0) w[i][j]=new fox(i,j);

else if(i%3==0 && j%2==0) w[i][j]=new rabbit(i,j); else if(i%5==0) w[i][j]=new grass(i,j);

else w[i][j]=new empty(i,j);

}

}

// вывод содержимого модели мира на экран

89

void pr_state(world w) { int i,j; for(i=0;i<N;++i)

{cout<<endl;

for(j=0;j<N;++j)

w[i][j]->print();

}

cout << endl;

}

 

 

 

 

 

 

 

 

 

 

 

 

Р

// новый world w_new рассчитывается из старого world w_old

 

void update(world w_new, world w_old)

 

 

 

 

 

{ int i,j;

 

 

 

 

 

 

 

 

 

 

У

for(i=0;i<N;++i)

 

 

 

 

 

 

 

Г

И

for(j=0;j<N;++j)

 

 

 

 

 

 

w_new[i][j]=w_old[i][j]->next(w_old);

 

 

 

 

 

 

}

 

 

 

 

 

 

 

а

 

 

 

 

// очистка мира

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Б

 

 

 

void dele(world w)

 

 

 

к

 

 

 

{ int i,j;

 

 

 

 

 

 

 

 

 

 

 

Модель имеет odd и even мир. Ихсмена является основой для расчета по-

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

 

 

 

 

 

 

 

 

 

 

for(j=1;j<N-1;++j) delete(w[i][j]);

 

 

 

 

 

 

 

}

 

 

 

 

 

т

 

 

 

 

 

 

 

следующего цикла.

 

 

о

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

int main()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

{ world odd,even;

 

 

 

 

 

 

 

 

 

 

 

int i;

 

л

 

 

 

 

 

 

 

 

 

 

б

 

 

 

 

 

 

 

 

 

 

 

init(odd);

 

 

 

 

 

 

 

 

 

 

 

 

init(even);

 

 

 

 

 

 

 

 

 

 

 

 

gener(even);

 

 

 

// генерация начального мира

 

 

cout<<"1 цикл жизни модели"<<endl;

 

 

 

 

 

 

Б

 

 

 

 

 

// вывод сгенерированной модели

 

pr state(even);

 

 

 

 

for(i=0;i<CYCLESи

-1;++i)

//цикл моделирования

 

 

 

 

{ getch();

 

 

 

 

 

 

 

 

 

 

 

 

cout<<i+2<<" цикл жизни модели"<<endl;

 

 

 

 

 

if(i%2)

 

 

 

 

 

 

 

 

 

 

 

 

{ update(even,odd);

// создание even модели из odd модели

 

pr_state(even);

 

 

// вывод сгенерированной модели even

 

dele(odd);

 

 

 

// удаление модели odd

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

90

 

 

 

 

 

 

 

 

 

 

 

 

 

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]