Класове и обекти 1 Печат
Написано от sevda   
Вторник, 30 Април 2013 07:24

Класове и обекти

Дефиниране на класовете. Обекти (екземпляри на класовете)

Класът е шаблон, чрез който може да се създават обекти. Той съдържа една дефиниция за състоянието на описателите и методите на обекта.

Дефиниция на клас.

Декларация на клас:

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 и методите на класовете

¨                   При създаване на обекти към един клас кодът на методите на този клас не се копира във всеки обект, а се намира само  в едно място в паметта.

¨                   При извикването на един метод, освен параметрите, описани в неговата декларация, неявно се предава още един параметър, който е указател към обекта, за който е извикан метода (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;

}                             

1.7.2.Предефинирани конструктори

Един клас може да има няколко конструктора с едно и също име (името на класа), но трябва да се различават по броя и или типа на параметрите си.

При създаването на обекти се изпълнява само един от предефинираните конструктори в зависимост от броя и/или типа на предаваните фактически параметри.

Предефинираните конструктори дават възможност различните обекти на един и същи клас да бъдат инициализирани по различен начин. 

1.7.3.Подразбиращ се конструктор

Конструкторите на класовете, както и всички останали функции могат да имат подразбиращи се параметри.

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

¨                                   Основната разлика между обединенията от една страна и структурите  и класовете от друга, се състои в това, че във всеки момент само един от компонентите на обединенията е “активен”.

¨                                   Върху обединенията са наложени следните ограничения, които не се отнасят за структурите и класовете:

  1. Всички компоненти на обединенията са достъпни за външни функции, т.е. всички компоненти са public. Достъпът до тях не може да бъде ограничаван чрез декларирането им като private или protected.
  2. Инициализацията на обединенията включва задаване на начална стойност само на компонента, който е деклариран на първо място, например:

union u {

int i;

float y;

char *s;

} x={20}; // Начална стойност на компонента i

  1. Обединенията могат да имат конструктори, но не могат да бъдат производни от други класове или базови за други класове.
  2. Анонимни обединения могат да съдържат само данни, но не и методи.

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 компоненти на тези класове.