Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Структуры данных / Си структуры данных2.doc
Скачиваний:
107
Добавлен:
23.02.2015
Размер:
1.36 Mб
Скачать

7. Классы и объекты

По мере прогресса в области вычислительной математики акцент в программировании смещается в какую-либо сторону. Первой была идея процедурного структурирования программ, затем – организация данных. В настоящее время акцент делается на объектно-ориентированное программирование(ООП).

Его руководящая идея заключается в стремлении связать данные с обрабатывающими эти данные функциями в единое целое – объект.

Класс (class) и объект (object) – два общепринятых термина. Однако, поскольку имеется несколько различных трактовок этих понятий, давайте сразу договоримся о том, как их будем понимать мы. Классом называется определенный пользователем тип данных, который включает в себя состояние (представление класса) и некие операции (поведение класса). Класс имеет некоторое количество внутренних данных и несколько методов, существующих в форме функций, и обычно описывает общее поведение и характеристики набора аналогичных друг другу объектов.

Объект есть экземпляр класса или, другими словами, переменная, тип которой является классом. Объекты в отличие от классов реальны в том смысле, что во время выполнения программы они хранятся в памяти. Соотношения между объектом и классом аналогичны соотношениям между переменной и типом.

К сожалению, в некоторых языках и средах эта разница не столь ясна. Дополнительную сложность создает также то обстоятельство, что ранние версии компилятора Borland Pascal использовали ключевое слово object для определения классов. По этой причине программисты на Pascal со стажем предпочитают использовать для обозначения типа термин “объект” вместо термина “класс”, а для обозначения реальных объектов - термин “экземпляр объекта” (object instance).

Чтобы определить в С++ новый класс данных, имеющий свои поля данных и методы, используется следующий синтаксис:

class СDate

{

int Month, Day, Year;

public:

void SetValue( int m, int d, int y );

bool LeapYear();

};

Методы класса должны быть реализованы в коде: чтобы подчеркнуть, что они являются частью класса Tdate.

В языке С++ принимается соглашение об использование трефикса С перед именем каждого определяемого класса. Это лишь соглашение, поскольку компилятор воспринимает символ С точно так же, как и все остальные буквы, но оно настолько распространено, что следование ему сделает ваш код значительно понятнее. Другое соглашение заключается в том, чтобы использовать двух- или трехбуквенный префикс для указания разработчика класса ( фирмы или конкретного человека). Это соглашение является общепринятым для компонентов. ( Например: cl_Date )

Для илюстрации использования объектов в программах, приведен класс простейшего связного списка. Этот список является двусвязным, и содержит объекты типа Node. Обратите внимание, что список имеет один фиктивный элемент. Первый элемент списка не содержит информации и является вспомагательным.

Класс имеет два конструктора, для создания пустого списка или клона к уже имеющемуся и заполненному списку, а так же свой оператор присваивания.

typedef class Node* link;

class Node{ public: // класс элемента списка

char* str;

link next;

link prev;

Node(){ str = NULL; next = NULL; prev = NULL; }

~Node(){ if( str ) delete str; str = NULL;

if( next ) delete next; next = NULL; prev = NULL; }

};

class List { // класс списка

public:

link head; // указатель на начало списка

link last; // указатель на конец списка

public:

List(){

head = NULL; last = NULL;

CreatList();

}

List( List& lt ) {

if( lt.head )

{

head = new Node;

CopyList( head, lt.head );

}

}

~List()

{

if( head ) DeleteList( head ); last = head;

}

void Set() // функция очистит список

{

if( head ) DeleteList( head ); last = head;

}

void Set( const List& lt )

{

if( head ) DeleteList( head );

if( lt.head )

{

head = new Node;

CopyList( head, lt.head );

}

}

const List& operator = ( const List& lt )

{

if( head ) DeleteList( head );

if( lt.head!=NULL )

{

head = new Node;

CopyList( head, lt.head );

}

return *this;

}

private: // служебные функции класса

// функция копирования списка

void CopyList( link dest, link source )

{

if ( source )

{

if( source->str )

{

dest->str = new char [ strlen(source->str)+1 ];

strcpy( dest->str, source->str );

}

if( source->next )

{

dest->next = new Node;

dest->next->prev = dest;

CopyList( dest->next, source->next);

}

else

{

dest->next = NULL;

last = dest;

}

}

}

// функция удаления списка

void DeleteList( link node )

{

if( node )

{

delete node;

}

node=NULL;

}

// функция создания нового списка

void CreatList()

{

if ( head == NULL )

{

head = new Node;

head->next = NULL;

head->prev = NULL;

last = head;

}

}

public:

// функция добавления элемента в конец

void AddNodeToEnd( const Node& nd )

{

link curr = new Node;

curr->str = new char [ strlen(nd.str)+1 ];

strcpy( curr->str, nd.str );

curr->next = NULL;

curr->prev = last;

last->next = curr;

last = curr;

}

// функция добавления элемента в начало

void AddNodeToBegin( const Node& nd )

{

link curr = new Node;

curr->str = new char [ strlen(nd.str)+1 ];

strcpy( curr->str, nd.str );

curr->next = head->next;

curr->prev = head;

head->next = curr;

}

// функция печати списка по порядку

void PrintListForward()

{

if ( head != NULL && head->next != NULL )

{

link curr = head->next;

int k = 1;

printf( "\n\nText:\n" );

while( curr )

{

printf( "Line %2d -> %s\n", k++, curr->str );

curr = curr->next;

}

}

}

// функция печати списка в обратном порядке

void PrintListBack()

{

if ( head != NULL && last != NULL )

{

link curr = last;

int k = 1;

printf( "\n\nText:\n" );

while( curr->prev )

{

printf( "Line %2d -> %s\n", k++, curr->str );

curr = curr->prev;

}

}

}

};

// демонстрация использования класса

int main()

{

Node a; // создание элемента

a.str = new char[100];

strcpy( a.str, "String 1" );

List list1; // создание списка

List1.AddNodeToEnd( a ); // добавление в конец

strcpy( a.str, "String 2" );

list1.AddNodeToEnd( a );

strcpy( a.str, "String 3" );

list1.AddNodeToEnd( a );

strcpy( a.str, "String 4" );

list1.AddNodeToBegin( a ); // добавление в начало

list1.PrintListForward();

List list2( list1 ); // создание другого списка копированием

list2.PrintListBack();

printf("\n");

return 0;

};

Обратите внимание, что при копировании списка происходит выделение памяти и копирование непосредственно каждого элемента. Ни в коем случае нельзя просто присвоить указателю на начало списка значение указателя на начало другого списка, т.к. при изменение данных в одном списке, произойдет изменение данных другого списка, а при удалении списка, элементы будут удаляться дважды, что приведет к ошибкам.