Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Бичков - Основи сучасного програмування.doc
Скачиваний:
69
Добавлен:
07.03.2016
Размер:
2.67 Mб
Скачать

7.10.2. Чисті віртуальні функції. Абстрактні класи

Чиста вiртуальна функцiя-член – це прототип функції, для якої не потріб­не визначення в протоколі класу. Синтаксично чиста віртуальна фун­кція задається так:

virtual<тип><iм'я>(сигнатура)=0;

Клас, який мiстить чисті вiртуальнi функцiї, називається абстрактним. Наприклад:

class AbstractClass {

public:

Virtual void f1(void);

virtual void f2(void)=0;//...};

Специфіка абстрактного класу полягає в тому, що він не може мати екземплярів. При оголошенні AbstractClass my; відбудеться помилка на етапі компіляції. Для використання абстрактного класу необхідно визначити похідний від нього клас, у якому чиста віртуальна функція оголошується як звичайна віртуальна. Причому в цьому випадку вона повинна мати тіло. Розглянемо клас

class MyClass:public AbstractClass{

public:

Virtual void f2(void);//...}

void MyClass::f2(void){\\тіло}

Звернемо увагу на те, що в класі MyClass f2() є вже звичайною вір­туальною функцією, отже, має бути її визначення (у даному випадку – за межами формального опису класу). Тоді можна буде описати екземпляр класу MyClass.

Чиста віртуальна функція може вільно використовуватись у протоколі абстрактного класу.

Похідний клас, який не визначає всі чисті віртуальні функції базового, також абстрактний. Напишемо програму, яка маніпулює з множинами без урахування їх типів:

#include <stdio.h>

#include <iostream.h>

#include <stdlib.h>

#include <string.h>

class Element;

typedef Element*PElem;

typedef PElem*PPElem;

class Set;

typedef Set*PSet;

class Set{

private:

int max; //-кiлькiсть елементiв

Int index;

PPElem set;

protected:

virtual int CompareElem(PElem P1,PElem P2)=0;

public:

Set(int n)

{max=n;index=0;

set=new PElem[n];}

virtual~Set()

{delete[]set;}

void AddElem(PElem p);

int HasElem(PElem p);

};

void Set::AddElem(PElem p)

{if(set==NULL)

{cout<<"\nError";

exit(1);}

if(index>=max){

cout<<"\nError,Set limit excluded";

exit(1);}

set[index]=p;

++index;}

int Set::HasElem(PElem p)

{if(set==NULL)return 0;

for(int i=0;i<index;i++)

if(CompareElem(p,set[i])==0)

return 1;return 0;}

Запишемо визначений клас Set у файл Set.h:

#include"set.h"

class Element{

private:

char*sp;

public:

Element(const char*s)

{sp=strdup(s);}

virtual~Element(){delete sp;}

virtual const char*GetString(void)

{return sp;}

};

class Myset:public Set{

protected:

virtual int CompareElem(PElem p1,PElem p2)

{

return strcmp(p1->GetString(),p2->GetString());

};

public:

Myset(int n):Set(n){}

};

void Test(const char*s,PSet setp)

{Element testElem(s);

if(setp->HasElem(& testElem))

cout<<"yes";

else cout<<"No";}

main()

{Myset t(4);

t.AddElem(new Element("Sep"));

t.AddElem(new Element("Jan"));

t.AddElem(new Element("Feb"));

t.AddElem(new Element("Mar"));

Test("Jan",&t);

return 0;}

Переваги використання абстрактних класів:

 модуль Set можна скомпілювати раніше та зберегти в бібліотеці класу;

 клас Set може використовувати інші програми, причому повторно компілювати файл Set не потрібно;

 при проектуванні абстрактних класів бажано розміщувати в них кілька віртуальних функцій-членів, якщо вони можуть бути корисними;

 наявність віртуальних деструкторів.