Най-четените учебни материали
Най-новите учебни материали
***ДОСТЪП ДО САЙТА***
ДО МОМЕНТА НИ ПОСЕТИХА НАД 2 500 000 ПОТРЕБИТЕЛИ
БЕЗПЛАТНИТЕ УЧЕБНИ МАТЕРИАЛИ ПРИ НАС СА НАД 7 700
Ако сме Ви били полезни, моля да изпратите SMS с текст STG на номер 1092. Цената на SMS е 2,40 лв. с ДДС.
Вашият СМС ще допринесе за обогатяване съдържанието на сайта.
SMS Login
За да използвате ПЪЛНОТО съдържание на сайта изпратете SMS с текст STG на номер 1092 (обща стойност 2.40лв.)Класове и обекти 1 |
![]() |
![]() |
![]() |
Класове и обектиДефиниране на класовете. Обекти (екземпляри на класовете)Класът е шаблон, чрез който може да се създават обекти. Той съдържа една дефиниция за състоянието на описателите и методите на обекта. Дефиниция на клас. Декларация на клас: class [] { Декларации на компонентите }; #include //Декларация на клас Person class Person { char name[20]; unsigned age; public: void getData(); void display() // Вградена функция (inline) {cout <<"Име: "< }; //Дефиниция на метода getData void Person::getData() { cout name; cout <<'\n'; cout age; cout <<'\n'; } void main () { Person mary,john; // mary и john са обекти на класа person mary.getData(); mary.display(); john.getData(); john.display(); } Създаването на обекти към даден клас е аналогично на дефинирането на дефинирането на променливи от даден тип: Person john, mary; // john и mary са обекти на класа Person Достъпът до компонентите на обектите се осъществява чрез задаване на името на обекта и името на компонента, разделени с точка: mary.display(); john.display(); ¨ Методите на даден клас имат достъп до всички негови компоненти (пряк достъп). ¨ Режимът на достъп до компонентите на класовете по отношение на външната среда (функциите, които не са методи на класовете) се регламентират от начина на деклариране на компонентите. ¨ Всеки компонент на даден клас може да бъде деклариран като private, public или protected. ¨ По подразбиране компонентите на класовете са private. ¨ Чрез използването на компоненти, декларирани като private, се постига скриване на информацията за външната спрямо обектите среда (капсулиране). #include //Декларация на клас Person class Person { char name[20]; unsigned age; public: void getData(); void display() // Вградена функция (inline) {cout <<"Име: "< }; //Дефиниция на метода getData void Person::getData() { cout name; cout <<'\n'; cout age; cout <<'\n'; } void main () { Person *ptr;//Деклариране на указател към класа Person Person george;//Създаване на обект george Person ptr = &george;//Инициалициране на указателя ptr. ptr сочи //обект george (*ptr).getData();//Извикване на getData() за обекта (*ptr).display();//Извикване на display() за обекта Синтактичната конструкция (*ptr) e еквивалентна на ptr-> ptr->getData(); ptr->display(); Обектите могат да бъдат създавани и унищожавани по време на изпълнение чрез операторите new и delete. Person *ptr; // Деклариране на указател към класа Person ptr = new Person; // Създаване на обект от класа Person delete ptr; // Унищожаване на обект от класа Person ¨ При създаване на обекти към един клас кодът на методите на този клас не се копира във всеки обект, а се намира само в едно място в паметта. ¨ При извикването на един метод, освен параметрите, описани в неговата декларация, неявно се предава още един параметър, който е указател към обекта, за който е извикан метода (this). #include class cl{ private: int x; public: void increm(){ x=0; x++; cout< } }; void main() { cl obj1,obj2; obj1.increm(); obj2.increm(); } ¨ За деклариране на статичните данни на класовете се използва ключовата дума static. Статичните данни на класовете имат следните особености: ¨ Паметта за статичните данни на даден клас се заделя еднократно и всички обекти на този клас имат достъп до нея. ¨ Статичните данни на класовете имат статус на външни променливи, поради което могат да се използват самостоятелно, а не само в контекста на обектите. ¨ Достъпът до статичните данни на класовете може да се осъществи от всяка функция чрез използване на пълния им идентификатор, който се състои от името на класа, оператора :: и името на статичната променлива. #include class cl1 { public: int x; static int y;// Стаична промелива-обща за всички // обекти на класа cl1 }; int cl1::y=2; // Инициализирането на статичните данни на класа е // задължително. В този момент се заделя памет void main() { cl1 a,b; //Създаване на два обекта на класа cl1 a.x = a.y = 3; // Инициалициране на a.x и a.y cout <<"a.y = "< b.y =4; cout <<"a.y = "< } ¨ За разлика от обикновените методи, статичните методи могат да бъдат извиквани самостоятелно, а не само в контекста на обектите. ¨ Самостоятелното извикване на статичните методи изисква използване на техните пълни имена (има на класа, оператор:: и има на метода). // Динамична памет в рамките на методите #include #include // Заради функцията strcpy() class Person{ private: char *name; unsigned age; public: void getData(); void display(); }; void Person::getData() { static char buf[20]; cout <<”Въведете име “<<’\n’; cin>>buf; name = new char[strlen(buf)+1]; strcpy (name, buf); cout <<”Въведете възраст “<<’\n’; cin >>age; } void dislplay() { cout <<” Име “< } void main() { Person mary, john; mary.getData(); john.getData(); mary.display(); john.display(); } Конструктори и деструктори ¨ Инициализация (задаване на начални стойности, заделяне на памет, запомняне на текущо състояние на програмата). ¨ Заключителни действия (освобождаване на преди това заделена памет, възстановяване на предварително запомнено състояние на програмата). Основни характеристики: ¨ Имената на конструкторите на даден клас съвпадат с името на този клас ¨ Конструкторите се изпълняват автоматично (без да се извикват явно) при създаване на обекти. Това правило е валидно и в случая, когато се създават динамични обекти чрез оператора new. ¨ Името на деструктора на едни клас се състои от името на този клас, предшествано от символа ~(тилда). ¨ Деструкторът на един клас се изпълнява автоматично (без да се извиква явно) всеки път, когато се унищожава обект на този клас. ¨ Типовете на върнатите стойности на конструкторите и деструкторите са съответно указател към новосъздаден обект (указателят this) и void. ¨ Адресите на конструкторите и деструкторите не могат да се присвояват на указатели. ¨ Един клас може да има многв конструктори, но само един деструктор. // Конструктор и деструктор на клас Person #include #include // Заради функцията strcpy() class Person{ char *name; unsigned age; Person(); // Конструктор public: ~Person(); {delete name;}// Деструктор, (inline) void display(); { cout <<” Име “< } }; // Дефиниция на конструктора Person::Person() { static char buf[20]; cout <<”Въведете име “<<’\n’; cin>>buf; name = new char[strlen(buf)+1]; strcpy (name, buf); cout <<”Въведете възраст “<<’\n’; cin >>age; } void main() { Person *ptr; ptr =new Persn[5]; for (int i=0; i<5; i++) (ptr +i)->display(); delete [] ptr; } Един клас може да има няколко конструктора с едно и също име (името на класа), но трябва да се различават по броя и или типа на параметрите си. При създаването на обекти се изпълнява само един от предефинираните конструктори в зависимост от броя и/или типа на предаваните фактически параметри. Предефинираните конструктори дават възможност различните обекти на един и същи клас да бъдат инициализирани по различен начин. Конструкторите на класовете, както и всички останали функции могат да имат подразбиращи се параметри. CL::CL(int, int=12); При използването конструктори с подразбиращи се параметри трябва да се има предвид следното ограничение: Недопустимо е в един същ клас да бъдат дефинирани подразбиращ се конструктор (конструктор без параметри) и конструктор с един подразбиращ се параметър. Конструкторите на класовете, както всички останали функции, могат да имат подразбиращи се параметри. Пример: CL::CL(int, int = 10); Недопустимо е в един и същи клас да бъдат дефинирани подразбиращ се конструктор (конструктор без параметри) и конструктор с един подразбиращ се параметър. ¨ Дефинициите на структурите се различават от дефинициите на класовете само по тава, че вместо ключовата дума class се използва ключовата дума struct. //Декларация на структурата s struct s { int p; float q; void f( ); s( ) {p = q = 1;} // Конструктор }; // Дефиниция на метод f void s::f( ) { … } // Дефиниция на функцията main void main ( ) { s x; //Създаване на обект х от тип структури x.f( ); x.p = x.q = 2; } ¨ Компонентите на структурите могат да бъдат данни и функции (методи), като достъпът до тях се осъществява по същия начин, както компонентите на класовете. ¨ За разлика от компонентите на класовете, компонентите на структурите по подразбиране са public, а не private. ¨ Обединенията са типове, които до голяма степен се подчиняват на същите синтактични правила, както е структурите. ¨ Дефинициите на обединенията се различават от дефинициите на структурите по това, че вместо ключовата struct се използва ключовата дума union. union un { int x; float y; }; un unionobj; //Създаване на обект от тип un ¨ Основната разлика между обединенията от една страна и структурите и класовете от друга, се състои в това, че във всеки момент само един от компонентите на обединенията е “активен”. ¨ Върху обединенията са наложени следните ограничения, които не се отнасят за структурите и класовете: union u { int i; float y; char *s; } x={20}; // Начална стойност на компонента i 1.9. Битови полета В рамките на класовете, структурите и обединенията могат да се дефинират данни (променливи) като се указва тяхната дължина в битове. Такива компоненти се наричат битови полета или просто полета. Синтаксис: [ : Допустимите типове на полетата са char, unsigned char, int и unsigned int. Битовите полета се заделят в рамките на една дума (два байта) в посока от младшите към старшите битове. Дължината, която се задава в декларациите, трябва да бъде константа от 0 до 15. Възможно е при декларацията на дадено битове поле да не се укаже неговото име. В този случай за полето се заделят необходимия брой битове, но те ще бъдат недостъпни. Достъпът до битовите полета се осъществява по същия начин, както се осъществява достъпът до обикновените компоненти на класовете и структурите. Пример: struct s1 { int x : 2; unsigned y : 5; int k : 1; int : 5; unsigned m: 3; Паметта, необходима за всеки обект на тази структура ще бъде една дума (16 бита). Разположението на битовите полета в рамките на тази дума е следното: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 m анонимно поле k y x Обекти и функции. Област на действие (видимост ) на обектите и класовете Отношението между функциите и обектите е същото, както е отношението между функциите и обикновените променливи. Обектите могат да се предават като параметри на функциите, да бъдат върнати стойности в резултат на изпълнение на функциите. Обектите могат да се предават като параметри на функциите по стойност, чрез указатели и чрез псевдоними. Пример: // Предаване на обект като параметър на функция // Декларация на клас Х class X { int x; float y; public: X( ) {x=1; y=2.5;} // Конструктор store ( ) {coutx>>y; cout<<’\n’;} show( ) {cout<<”x= “< //Дефиниция на функцията f1 void f1 (X p) // Параметърът е обект – предаване по стойност { p.store( ); p.show( ); } //Дефиниция на функцията f2 Void f2 (X *p) //Параметърът е указател { p->store( ); p->show( ); } //Дефиниция на функцията f3 void f3 (X &p) // Параметърът е псевдоним { p.store( ); p.show( ); } // Дефиниция на функцията main void main( ) { X obj; obj.store( ); obj.show( ); // Тестов печат f1(obj); // Предаване по стойност obj.show( ); // Тестов печат f2(&obj); // Предаване чрез указател obj.show( ); // Тестов печат f3(obj); // Предаване чрез псевдоним obj.show( ); // Тестов печат } 1.10 Приятели на класовете Приятели на класовете могат да бъдат функции, други класове и отделни методи на други класове. Приятелите на един клас трябва да бъдат декларирани в рамките на класа с помощта на спецификатора friend. Пример: class X { private: int value; … friend int R::f1(X*); // Метод –приятел на клас Х friend void Z::f3(X&); // Метод-приятел на клас Х friend float f (int,X&); // Функция-приятел на клас Х friend class Y; // Клас-приятел на клас Х }; Приятелите на даден клас имат достъп до всички негови компоненти. ¨ Едно характерно приложение на функциите-приятели е осъществяването на информационни връзки между различни класове. //Използване на функция-приятел #include class B; //Непълна декларация на клас В. Необходима е, тъй като класът В е // дефиниран след класа А, а се използва в класа А като параметър // на функцията swap // Дефиниция на клас А class A { int value; friend void swap (A &, B &); //Функция-приятел – има достъп до // private компонента value public: A( ) {cout value; cout<<’\n’;} void disp( ) { cout<<” value = “< //Дефиниция на клас В class B { int x; float y; friend void swap (A &, B &);//Функция-приятел – има достъп до //private компонентите х и у public: B( ) //Вграден конструктор {coutx>>y; cout<<’\n’;} void disp( ) {cout<< “x= “< }; Дефиниция на функцията swap void swap (A &p, B &q) { int buf; buf=p.value; p.value=q.x; q.x=buf; } // Дефиниция на функцията main void main( ) { A obj1; B obj2; swap (obj1, obj2); //Замяна на стойностите obj1.value и obj2.x obj1.disp( ); // Извеждане на стойността на value obj2.disp( ); // Извеждане на стойността на х } Функцията swap, дефинирана в тази програма, разменя стойностите на компонентите value и x на обектите, които получава като параметри. За да има достъп до тези компоненти, функцията swap е декларирана като функция-приятел на класовете А и В, тъй като компонентите value и х са private компоненти на тези класове. |