Вызов метода и доступ к элементам класса

Методы выполняют операции над объектами класса. Поэтому при обращении к функции Getx необходимо указать, с каким объектом класса Point следует работать. Если бы Getx была обычной функцией языка С (или не мето­дом С++) эта проблема не возникла бы: функция вызывалась бы простым об­ращением к Getx().

Чтобы вызвать метод класса в той части программы, которая не является частью класса, надо использовать имя объекта и операцию точка (.) для досту­па к элементу класса, аналогично обращению к элементам структуры языка С, согласно форме:

имя_объекта . имя_метода (список аргументов)

имя_объекта . имя_элемента_данных

Например, пусть описаны объекты класса:

Point p1, p2, *pp;

Тогда возможные обращения к элементам класса имеют вид:

p1. X; // доступ к элементу Х объекта р1

p2.Y; // доступ к элементу Y объекта р2

p1. Getx(); // вызов метода Getx()

С другой стороны, метод класса может вызвать другой метод того же клас­са или использовать данные-элементы класса непосредственно, не используя операцию точка.

Вывод. Операцию точка надо использовать только тогда, когда метод клас­са вызывается в функциях, не являющихся элементами класса.

Если имеется указатель на объект типа Point, следует применять опера­цию вызова метода посредством указателя, используя операцию "стрелка"
( ->): pp->Getx().

Рассмотрим программу, которая иллюстрирует особенности языка С++, обсуждавшиеся выше.

Пример 9.

Программа моделирования работы класса "очередь" с фиксированной дли­ной очереди.

#include<iostream.h>

#include<conio.h>

const int sizeq= 5 ; // размер очереди

class Queue // класс "очередь"

{ int q[sizeq]; // массив очереди

int head, tail; // начало и конец очереди

public: // прототипы методов класса:

void init(void); // инициализация очереди

void qput(int); // постановка в очередь

int qget(void); // выход из очереди

void show(); // вывод данных очереди

};

// описание методов класса:

void Queue::init(void) // метод инициализации очереди

{ tail=head=0; // исходное обнуление очереди

for(int i=0; i<sizeq; i++)

q[i]=0;

}

void Queue::qput(int i) // метод постановки в очередь

{ if(tail==sizeq) // если все места заняты, то сообщение

{ cout << "Очередь полна ";

return; // возврат из функции

}

q[tail++]=i; // увеличение очереди

}

int Queue::qget(void) // метод выхода из очереди

{ if(head==tail) // если достигнут конец очереди, то сообщение

{

cout << "Очередь пуста ";

return 1111; // возврат какого-либо значения

}

int i=q[head]; // значение уходящего элемента очереди

q[head++]; // сдвиг начала очереди к концу

return i; // возврат значения элемента очереди

}

void Queue::show() // метод вывода значений очереди

{cout<<"Значения: head="<<head<<" tail="<<tail<<"\nЭлементы очереди: ";

for(int i=0; i<sizeq; i++)

cout<<q[i]<<" ";

cout<<"\n";

}

int main() // главная функция

{ int i;

clrscr(); // чистка экрана результатов

cout<<"Создаем два объекта a, b:"<<"\n";

Queue a, b; // созданы объекты-очереди a, b

cout<<"Инициализация очереди а: ";

a.init();

a.show(); // вывод данных очереди а

// заполнение очереди а значениями:

a.qput(7);

a.qput(9);

a.qput(11);

cout<<"Очередь а: ";

a.show(); // вывод данных очереди а

cout<<"Вывод данных очереди а в цикле:\n";

for(i=0; i<sizeq; i++) // цикл вывода из очереди а

cout << a.qget() << " ";

cout<<"\n";

a.show(); // вывод данных очереди а

cout<<"\nИнициализация очереди b: ";

b.init();

b.show(); // вывод данных очереди b

for(i=0; i<sizeq+1; i++) // цикл заполнения очереди b

b.qput(i*i);

cout<<"\nОчередь b: ";

b.show(); // вывод данных очереди b

cout<<"Вывод данных очереди b в цикле:\n";

for(i=0; i<sizeq+1; i++) // вывод данных в цикле

cout<<b.qget()<<"";

cout<<"\n";

b.show(); // вывод данных очереди b

getch(); // задержка экрана результатов

return 0; // нормальное окончание программы

}

Результаты программы:

Создаем два объекта a, b:

Инициализация очереди а: Значения: head=0 tail=0

Элементы очереди: 0 0 0 0 0

Очередь а: Значения: head=0 tail=3

Элементы очереди: 7 9 11 0 0

7 9 1 Очередь пуста 1111

Значения: head=3 tail=3

Элементы очереди: 7 9 11 0 0

Инициализация очереди b: Значения: head=0 tail=0

Элементы очереди: 0 0 0 0 0

Очередь полна

Очередь b: Значения: head=0 tail=5

Элементы очереди: 01 4 9 16

Вывод данных очереди b в цикле: 01 4 9 16 Очередь пуста 1111

Значения: head=5 tail=5

Элементы очереди: 01 4 9 16

Особенностью этого примера является то, что функция main() стоит не на первом месте, как в программах на языке С. Обычно в программах С++ методы классов определяются перед main(). По мере возрастания объема программ объявления классов следует выделять в файлы заголовков, а определения мето­дов класса располагать в отдельно компилируемых исходных файлах С++.

Конструкторы и деструкторы

При создании объекты обычно инициализируются. Например, в классе очереди Queue (пример 9) это было реализовано функцией init(). Среди функ­ций класса имеются специальные методы, которые определяют особенности со­здания, инициализации, копирования и уничтожения объектов данного класса. Их называют конструкторы и деструкторы. Как и обычные методы, конструк­торы и деструкторы могут описываться в пределах или вне класса.

Конструктор это метод, основной целью которого является инициализа­ция переменных объекта данного класса или распределение памяти для их хра­нения (constructor – создатель объекта). С++ предоставляет возможность де­лать это автоматически при объявлении объекта, то есть при его создании. С объектом всегда связано либо явное, либо не явное выполнение конструктора. Конструктор вызывается в тот момент, когда создается объект класса, то есть ему выделяется место в памяти. Нельзя вызвать конструктор в явном виде в программе как обычную функцию. Он вызывается явно компилятором при со­здании объекта и неявно при выполнении оператора new, применяемого к объекту, а также при копировании объекта данного класса. Если конструктор не описан, то компилятор создает автоматически конструктор по умолчанию.

Конструктор имеет то же имя, что и класс, в котором он определен, но не может иметь тип возвращаемого значения, в том числе void. Конструктор в большинстве случаев никаких сообщений не выдает. Он может иметь парамет­ры, в том числе по умолчанию, может быть перегруженной функцией, то есть класс может иметь несколько разных конструкторов. Конструктор, не имеющий аргументов, называется конструктором по умолчанию.

Пример 10.

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

class Queue // класс "очередь"

{ int q[sizeq]; // массив очереди

int head, tail; // начало и конец очереди

public: // прототипы методов класса:

Queue (void); // это объявление конструктора в классе

void qput(int); // постановка в очередь

int qget(void); // выход из очереди

void show(); // вывод данных очереди

};

// описание (определение) конструктора Queue вне класса:

Queue :: Queue (void)

{ tail=head=0; // исходное обнуление очереди

for(int i=0; i<sizeq; i++)

q[i]=0;

}

Метод класса деструктор (destructor) разрушает объект данного класса и может вызываться явно с помощью оператора delete, либо неявно, выполняя действия перед окончанием работы объекта (освобождение памяти, восстанов­ление экрана, закрытие файлов и т. д.). Если деструктор не объявлен явно, компилятор генерирует его автоматически.

Деструктор имеет имя класса с символом тильда (~) перед ним. В отличие от конструктора он не может получать аргументы и быть перегруженной функцией.

Для статических объектов память распределяется компилятором: конструктор вызывается перед main, а деструктор — после main. Деструктор вызывается неявно, когда автоматическая (auto) переменная выходит из области действия. Например, объект является локальным внутри функции, и функция возвращает управление. В случае глобальных переменных деструкторы вызыва­ются как часть процедуры выхода после main.

При создании динамического объекта с помощью оператора new для уда­ления объекта, хранящегося в динамической памяти, явно используется опера­тор delete.

Деструкторы вызываются строго в обратной последовательности вызова соответствующих конструкторов.

Наши рекомендации