{
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;}
Переваги використання абстрактних класів:
a модуль Set можна скомпілювати раніше та зберегти в бібліотеці класу;
a клас Set може використовувати інші програми, причому повторно компілювати файл Set не потрібно;
a при проектуванні абстрактних класів бажано розміщувати в них кілька віртуальних функцій-членів, якщо вони можуть бути корисними;
a наявність віртуальних деструкторів.
Віртуальні деструктори
Деструктори, на відміну від конструкторів, можуть бути віртуальними. Синтаксично вони задаються, як і звичайні віртуальні функції, за допомогою ключового слова virtual. Віртуальні деструктори використовуються у випадку, коли в деякому класі необхідно знищити об'єкти похідного класу, на які посилаються покажчики на базовий клас. Розглянемо приклад:
class Base{
private:
char*sp1;
public:
Base(const char*s)
{sp1=strdup(s);}
virtual ~Base()
{delete sp1;}};
class Derived::public Base{
private:
char*sp2;
public:
Derived(const char*s1,const char*s2):Base(s1)
{sp2=strdup(s2);}
virtual~Derived()
{delete sp2;}};
Base*pbase;
pbase=new Derived("string1","string2");
Delete pbase; //s1-знищився,s2-залишився.
Якщо б у цьому прикладі деструктори не були віртуальними, то при виході з області видимості об'єкта класу Derived, на який указує покажчик pbase, викликався б лише деструктор класу Base, тобто копія рядка string2 залишилася б у пам'яті. Якщо ж деструктори оголошені як віртуальні, то в даній ситуації буде викликаний спочатку деструктор похідного класу, а потім – базового.
Посилання як засіб для реалізації поліморфізму
Для реалізації поліморфізму в С++, крім покажчиків, можна використовувати й посилання. Розглянемо приклад:
#include "form.h"
Main
{circle c1;
Line l1,l2;
shape & pic0=c1
shape & pic1=l1;
shape & pic2=l2;
pic0.Draw();
pic1.Draw();
pic2.Draw();}
У цьому прикладі кожен виклик функції Draw() приводить до зображення відповідної фігури.
При передаванні параметрів віртуальним функціям може виникнути помилка. Виникає питання: коли здійснюється контроль за помилками при передаванні параметрів? Адже конкретна реалізація віртуальної функції зв'язується з об'єктом на етапі виконання програми. Що стосується С++, то контроль за помилками при передаванні параметрів віртуальним функціям здійснюється на етапі компіляції, а не виконання програми, тому що сигнатури віртуальних функцій мають строго збігатися.