Класстар. Полиморфизм. Виртуалды функциялар. Операторлардың шамадан тыс жүктелуi

Автор: Пользователь скрыл имя, 11 Февраля 2013 в 21:00, лабораторная работа

Краткое описание

Полиморфизм(polymorphism грек тілінен)- бұл техникалық әртүрлi есептерді, бірақ ұқсас екі немесе бірнеше есепті шығару үшін бірдей атты қолдануға мүмкiндiк беретін қасиет. Полиморфизмның объектіге бағытталған программалауда қолдану мақсаты, бір атты тапсырмасы ортақ класс әдістері (для класса действий) үшін қолдану болып табылады. Әрбiр нақты әдістердің (действия) орындалуы мәлiметтер типімен анықталады.

Файлы: 1 файл

Polimorfizm.doc

— 186.00 Кб (Скачать)

Лабараториялық жұмыс 6

«Класстар. Полиморфизм. Виртуалды  функциялар.

Операторлардың шамадан тыс жүктелуi»

 

Мақсаты: Полиморфизм қағидаларымен танысу;

         Виртуалды функцияларды қолдануды үйрену;

                   Операторлардың шамадан тыс жүктеуiн оқу.

 

1. ТЕОРИЯЛЫҚ БӨЛІМ

1.1 Полиморфизм

Полиморфизм(polymorphism грек тілінен)- бұл техникалық әртүрлi есептерді, бірақ ұқсас екі немесе бірнеше есепті шығару үшін бірдей атты қолдануға мүмкiндiк беретін қасиет. Полиморфизмның объектіге бағытталған программалауда қолдану мақсаты, бір атты тапсырмасы ортақ класс әдістері (для класса действий) үшін қолдану болып табылады. Әрбiр нақты әдістердің (действия) орындалуы мәлiметтер типімен анықталады. Мысалы Си тiлі үшiн полиморфизмді қолдану жеткiлiксiз, себебі санның абсолюттiк шамасын табу үшін әр түрлі үш функция керек: abs(), labs() және fabs(). Бұл функциялар сәкесінше бүтін, ұзын бүтін (длинных целых) және жылжымалы нүктедегі санның абсолюттiк шамаларын есептеп қайтарады. Ал С++ тілінде осы аталған әр функция  abs() деп атала алады. Функцияны шақыру кезінде қолданылатын маліметтер типі, нақты қай функцияның орындалып жатқанын анықтайды. C++ тілінде функцияның бір атын әр түрлі әрекеттерді (действия) орындау барысында пайдалануға болады. Бұл функцияның жүктелуі (function overloading) деп аталады.

Жалпы полиморфизмның негізгі тұжырымдамасы «бiр интерфейс, көп әдіс" идеясы болып табылады. Яғни мағынасы жақын әдістер тобы үшін ортақ бір интерфейс құруға болады деген сөз. Плоиморфизмнің негізгі қасиеті күрделі программалардың орындалуын жеңілдетеді,  ол әр түрлі әдістерді орындау үшін бір ғана функцияны шақырып қолдануға мүмкіндік береді. Нақты бір әдісті алу программистке емес негізінен компиляторға жүктеледі, программист тек ортақ интерфейсті қолдануды ұмытпауы қажет.  
           Полиморфизм сонымен бiрге операторларға да қолданыла алады. Iс жүзiнде барлық 
программалау тілдерінде полиморфизм шектеулі түрде қолданылады, мысалы 
арифметикалық операторлар. «+» символы Си тілінде бүтін, ұзын бүтін, символды айнымалылар және жылжымалы нүктедегі сандарды қосу үшін қолданылады. Бұл жағдайда компилятор автоматты түрде арифметиканың қай типі керек екенін анықтайды. Ал С++ тілінде бұл концепцияны басқа да өзіміз берген мәліметтер типіне сәйкес қолдана аламыз. Полиморфизмнің бұндай түрі операторлардың жүктелуі (operator overloading) деп аталады. 

 

1.2 Функцияның жүктелуі

Функция жүктелуінің негізгі мақсаты  мынадай: бір атпен жазылған функция  әр түрлі орындалады және әр түрлі  мәндер мен типіне сәйкес әр түрлі  мәндер қайтарады. Жүктелу орындалу үшін, әрбір жүктелетін функцияның қайтаратын мәні мен айнымалыларын дәл сондай атпен жазылған басқа функциядан айырмашылығы болатындай етіп беру қажет. Компилятордың өзі типіне сәйкес берілген айнымалыны алатын қай функцияны алу керек екенін анықтайды.

Мысалы:

#include<iostream.h>

#include<string.h>

// int типті екі санды салыстыру

int max(int a,int b)

{

if(a>b) return a;

else return b;

}

// float типті екі санды  салыстыру

float max(float a,float b)

{

if(a>b) return a;

else return b;

}

// екі жолды салыстыру

char* max(char* a,char* b)

{

if(strcmp(a,b)>0) return a;

else return b;

}

void main()

{

int a1,b1;

float a2,b2;

char s1[20];

char s2[20];

cout<<"int tipi uwin:\n";

cout<<"a=";cin>>a1;

cout<<"b=";cin>>b1;

cout<<"MAX="<<max(a1,b1)<<"\n";

 

cout<<"\nfloat tipi uwin:\n";

cout<<"a=";cin>>a2;

cout<<"b=";cin>>b2;

cout<<"MAX="<<max(a2,b2)<<"\n";

 

cout<<"\nchar* tipi uwin:\n";

cout<<"a=";cin>>s1;

cout<<"b=";cin>>s2;

cout<<"MAX="<<max(s1,s2)<<"\n";

}

 

Жүктелген функциялардың негізгі ережелері:

  • Жүктелген функциялар көрінетін бір аймақта орналасуы қажет;
  • Жүктелген функциялардың мәндері үнсіз түрде болуы мүмкін (по умолчанию), және де әр түрлі функциядағы мәндер бірдей болуы қажет;
  • Егер функцияның  модификаторы const немесе функциялары int& f1(int&, const int&){…} және int f1(int,int){…} болса, функция жүктелмейді, себебі компилятор нақты қай функция шақырылып тұрғанын анықтай алмайды.  

 

1.3 Операторлардың шамадан тыс жүктелуі

Функцияның жүктелуі мен  операторлардың жүктелу механизмі тығыз байланысты. С++ тілінде көптеген операторларды нақты класстарға қатысты жүктеуге болады.

Операторларды жүктеу - С++ тілінде ең тиімді мүмкіндіктердің бірі болып табылады. Ол толығымен прогаммалау аймағындағы кездесетін жаңа класстарды интегралдауға мүмкіндік береді. Операциялардың жүктелуінен кейін жаңа класстағы объектілер дәл қоса салынған (встроенных) типтегі айнымалылар операциялары секілді болды. Сонымен қатар операторлардың жүктелуі   С++ тілінің енгізу - шығару негізінде  жатады.

Операторлардың жүктелуі сәйкес келетін класстағы объектіге қатысты жүктелетін операторлар әдістерін анықтайтын функция операторларының көмегімен жүзеге асады. Функция операторлары operator кілттік сөзі арқылы құрылады. Функция операторлары класс мүшелері де және қарапайым функцияларда бола алады. Бірақ қарапайым функциялар операторларды жүктейтін классқа ереже бойынша достық (friend) болып жарияланады, достық функциялар класстың қорғалған (защищенным) мүшелеріне рұқсат (доступ) ала алады.

Әрбір аталған оқиғадағы функция операторлары әр түрлі жарияланады, сол үшін бұл оқиғалар жеке - жеке қарастырылуы қажет.     

 

1.3.1 Операторлардың ішкі функциясы түрінде жүктелуі

 

Операторларды ішкі функция формасында жүктеу үшін глобальды функияны анықтау қажет.

#include<iostream>

using std::cout;

using std::endl;

#include<cstring>

class String

{

friend String& operator+(const String&, const String&);

private:

char *s;

public:

//Констркуторы и т.д.

};

String& operator+(const String& s1,const String& s2)

{

char *s=new char[strlen(s1.s)+strlen(s2.s)+1];

strcat(s,s1.s,s2.s);

String newStr(s);

delete s;

return newStr;

}

int main()

{

String s1="Hello";

String s2="Goodbye";

String s3=s1+s2;

}

 

Жүктелген функция кез келген глобалды функция секілді көрінеді. Дәл  осындай оқиғалар үшін достық функциялар ойлап табылған.  Егер де біз operator+ функциясын достық ретінде хабарламағанда, онда ол s айнымалысына рұқсат (доступ) ала алмайтын еді, және де бізге мынадай таңдау жасау керек болады: char* -ға бәріне бірдей доступ алуға рұқсат беру немесе әрбір сілтеме жасаған сайын жолдар көшіріліп отыратын тиімді орындауға ауысу. Концепциялы тұрғыдан қарағанда operator+ String кітапханасының бөлігі болып табылады, сондықтан бұл фукнцияны достық ретінде хабарлап және String кітапханасының ішкі құрылғысының кілтін беруге болады.

Ішкі функциялармен өзгерту  операторларынан басқа кез – келген операторлар жүктеле алады. =, [], (), және -> операторлары тек класс функциясымен жүктелуі тиіс.

 

1.3.2 Операторлардың  класс функциясы түрінде жүктелуі

Синтаксисі қарапайым класс  функциясын жүктеуге ұқсас, тек аргументтер саны ішкі функция түрімен салыстырғанда 1-ге қысқарады, бар болғаны сол.

#include<iostream>

using std::cout;

using std::endl;

#include<cstring>

class String

{

private:

char *s;

public:

//Констркуторы  и т.д.

String& operator+(const String&) const;

};

String& String::operator+(const String& s1) const

{

char *s2=new char[strlen(s1.s)+strlen(s)+1];

strcat(s2,s1,s);

String newStr(s2);

delete s2;

return newStr;

}

Main()

{

String s1="Hello";

String s2="Goodbye";

String s3=s1+s2;

return 0;

}

 

Кез келген оператор класс функциясы  түрінде жүктеле алады. Егер оператор ішкі функция секілді, класс функциясында жүктеле алатын болса, онда бізге  екі түрдің қайсысын таңдау қажет? Жауап: егер де бізге ішкі функциясында жүктеу үшін салмақты себеп жоқ болса, класс функциясы түрінде жүктеуді қолданған жөн. Себептері:

  1. Бірінші аргумент базалық типке жатады (мысалы, int немесе double).
  2. Модификациялауды қажет етпейтін, бірінші аргументтің типі коммерциялы кітапханада анықталған.

Компилятор жүктеуді бинарлы операторлардың сол жақ бөлімін және жалғыз унарлы аргументті қарастыра отырып, класс  функция түрінде іздейді. Ішкі функция  түрінде жүктеудің ең тараған  мысалы – ostream кітапханасындағы << операторы.

 

Osteram& operator<<(osteram& os, const String s )

{

os<<str.s; //берілген функция достық болып табылады деп болжаулуда

return os;

}

 

Жүктеу ішкі функция түрінде  жүзеге асырылу қажет, себебі типі String – оң жақта орналасқан.

 

1.3.3 Енгізу және шығару  операторларын жүктеу үшін достық функциясын қолдану схемасы

Шығару  операторын (<<) жүктеу үшін достық функциясын қолдану схемасы:

  1. Классты суреттеу бөлімінде шығару операциясын жүктеуді жүзеге асыратын достық функция туралы хабарлама орналастыру қажет

Class name_class

{

friend ostream & operator<<(ostream & os, const name_class & t );

};

  1. Іске асыру бөлімінде функция денесін орналастыру

ostream & operator<<(ostream & os, const name_class & t )

{os<<t.p1<<t.p2<<t.p3<<…<<endl;};

Мұнда: name_class – класс аты;

p1– класс экземплярының шығарылатын полясы

 

Енгізу  операторын (>>) жүктеу үшін достық функциясын қолдану схемасы:

  1. Классты суреттеу бөлімінде шығару операциясын жүктеуді жүзеге асыратын достық функция туралы хабарлама орналастыру қажет

Class name_class

{

friend istream & operator>>(istream & stream,  name_class & t );

};

  1. Іске асыру бөлімінде функция денесін орналастыру

istream & operator>>(istream & stream, name_class & t )

{stream>>t.p1>>t.p2>>t.p3>>…>>endl;};

Мұнда: name_class – класс аты;

p1– класс экземплярының шығарылатын полясы

 

1.3.4 Комплексті сандар үшін операцияларды жүктеуге мысал

#include<iostream>

using namespace std;

//Описание класса

class complex

{

float Re,Im;

public:

complex();

complex(float Re,float Im);

    void complex::show();

friend complex operator+(complex,complex);

friend ostream & operator<<(ostream & os,const complex & t);

};

//Реализация функций 

complex::complex() {}; //parametrsiz konstruktor

complex::complex(float x, float y) {Re=x; Im=y;};//parametrli konstruktor

complex operator+(complex a,complex b)

{

complex c;

c.Re=a.Re+b.Re;

c.Im=a.Im+b.Im;

return c;

};

ostream & operator<<(ostream & os, const complex & t)

{os<<t.Re<<" "<<t.Im<<endl;};

//Головная программа

main()

{

complex a(2,3),b(5,6),c;

c=a+b;

cout<<c;

system("pause");

}

 

1.4 Виртуалды функциялар

Виртуалды функциялар механизімі әрбір туынды класста өзінше бір (свой) кейбір компонентті функциялар қажет болған жағдайда қолданылады. Осындай функцияларды қабылдайтын класстар полиморфты деп аталады және ОБП-да маңызды рөл атқарады.

     Виртуалды функциялар кешірек (позднего) немесе динамикалық байланыс (динамического связывания) механизімін ұсынады. Базалық класстың  статикалық емес кез – келген функциясы виртуалды болып табылуы мүмкін және де virtual кілттік сөзін қолданады. 

Мысалы

class base

{

public:

virtual void print() {cout<<”\nbase”;}

};

 

class dir:public base

{

public:

void print() {cout<<”\ndir”;}

};

void main()

{

base B, *bp=&B;

dir D, *dp=&D;

base *p=&D;

bp->print();//base

dp->print();//dir

p->print();//dir

}

Демек,  әрбiр виртуалды функцияның базалық классқа нұсқағыш арқылы шақыру интерпретациясы дәл сол нұсқағыштың мәніне тәуелдi болады, яғни шақыру орындалып жатқан объектінің типіне тәуелді.

Информация о работе Класстар. Полиморфизм. Виртуалды функциялар. Операторлардың шамадан тыс жүктелуi