Методы класса внутри определения класса

Методы класса smallobj выполняют действия, типичные для методов классов во­обще: они считывают и присваивают значения полям класса. Метод setdata() принимает apгумент и присваивает полю somedata значение, равное значению ар­гумента. Метод showdata() отображает на экране значение поля somedata.

Обратите внимание на то, что функции setdata() и showdata() определены внутри класса, то есть код функции содержится непосредственно в определении класса (здесь определение функции не означает, что код функции помещается в память. Это происходит лишь при создании объекта класса). Методы клас­са, определенные подобным образом, по умолчанию являются встраиваемыми. Позже мы увидим, что функции внутри класса можно не только определять, но и объявлять, а оп­ределение функции производить в другом месте. Функция, определенная вне класса, по умолчанию уже не является встраиваемой.

 

Использование класса

Теперь, когда класс определен, давайте рассмотрим, каким образом его можно использовать в функции main(). Мы увидим, как определяются объекты и каким образом организован доступ к методам уже определенных объектов.

Определение объектов

Первым оператором функции main() является

smallobj s, s2:

Этот оператор определяет два объекта s1 и s2 класса smallobj. Обратите вни­мание на то, что при определении класса smallobj не создаются никакие его объекты. Определение класса лишь задает вид будущего объекта, подобно тому, как определение структуры не выделяет память под структурные переменные, а лишь описывает их организацию. Все операции программа производит с объ­ектами. Определение объекта похоже на определение переменной: оно означает выделение памяти, необходимой для хранения объекта.

 

Вызов методов класса

Следующая пара операторов осуществляет вызов метода setdata():

sl.setdata(1066); sl.setdata(1776);

Эти операторы выглядят не так, как обычный вызов функции. Почему имена объектов si и s2 связаны с именами функций операцией точки (.)? Такой стран­ный синтаксис объясняется тем, что вызов применим к методу конкретного объ­екта. Поскольку setdata() является методом класса smallobj, его вызов должен быть связан с объектом этого класса. Например, оператор

setdata(1066);

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

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

Оператор sl.setdata(1066):

вызывает метод setdata() объекта si. Метод присваивает полю somedata объекта si значение, равное 1066. Вызов

s2.setdata(1776):

подобным же образом присваивает полю somedata объекта s2 значение, равное 1776.

Аналогично, два вызова функции showdata() отобразят на экране значения полей соответствующих объектов:

s1. showdata(): s2. showdata():

Объекты программы и объекты реального мира

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

 

Детали изделия в качестве объектов

Класс smallobj из предыдущего примера содержал только одно поле данных. Теперь мы рассмотрим более интересный пример.

// objpart.cpp

// детали изделия в качестве объектов

#include <iostream>

using namespace std;

//////////////////////////////////////////////////////////

class part  // определение класса

{

private:

int modelnumber; // номер изделия

int partnumber;   // номер детали

float cost;  // стоимость детали

public:

// установка данных

void setpart(int mn, int pn, float c)

{

modelnumber = mn;

partnumber = pn;

cost = c;

}

void showpart()

       // вывод данных

{

cout << "Модель " << modelnumber;

cout << ". деталь " << partnumber;

cout << ". стоимость $" << cost << endl;

}

};

//////////////////////////////////////////////////////////

int main()

{

setlocale(LC_CTYPE, "rus");

part part1; // определение объекта

// класса part

part1.setpart(6244, 373, 217.55F); // вызов метода

part1.showpart(); // вызов метода

return 0;

}

 

 

В этой программе используется класс part. В отличие от класса smallobj, класс part состоит из трех полей: modelnumber, partnumber и cost. Метод класса setpart() присваивает значения всем трем полям класса одновременно. Другой метод, showpart(), выводит на экран содержимое полей.

В примере создается единственный объект класса part с именем parti. Метод setpart() присваивает его полям значения соответственно 6244, 373 и 217.55. Затем метод showpart() выводит эти значения на экран. Результат работы програм­мы выглядит следующим образом:

Модель 6244. деталь 373. цена $217.55

Этот пример уже ближе к реальной жизни, чем SMALLOBJ. Если бы вы разра­батывали инвентаризационную программу, то, вероятно, создали бы класс, ана­логичный классу part. Мы привели пример объекта С++, моделирующего реаль­но существующий объект — комплектующие изделия.

Класс как тип данных

Здесь мы рассмотрим пример, демонстрирующий применение объектов С++ в ка­честве переменных типа, определенного пользователем. Объекты будут представ­лять расстояния, выраженные в английской системе мер. Ниже приведен листинг программы ENGLOBJ:

// englobj.cpp

// длины в английской системе в качестве объектов

#include <iostream>

using namespace std;

//////////////////////////////////////////////////////////

class Distance    // длина в английской системе

{

private:

int feet;

float inches;

public:

void setdist(int ft, float in) // установка значений полей

     { feet = ft;

        inches = in; }

  void getdist() // ввод полей с клавиатуры

     {

       cout << "\nВведите число футов: ";

        cin >> feet;

        cout << "Введите число дюймов: ";

        cin >> inches;

      }

     void showdist()     // вывод полей на экран

       { cout << feet << "\'-" << inches << "'\'"; }

       };

//////////////////////////////////////////////////////////

int main()

{

setlocale(LC_CTYPE, "rus");

Distance dist1, dist2;     // две длины

dist1.setdist(11,6.25);    // установка значений для dl

dist2.getdist();      // ввод значений для dist2

// вывод длин на экран

cout << "\nd1stl - ";

dist1.showdist();

cout << "\ndist2 - ";

dist2.showdist();

cout << endl;

return 0;

}

В этой программе класс Distance содержит два поля: feet и inches. Он схож со структурой Distance, рассмотренной ранее, однако класс Distance имеет три метода: setdist(), предназначенный для задания значений полей объекта через передаваемые ему аргументы, getdist(), получающий эти же значения с клавиа­туры, и showdist(), отображающий на экране расстояние в футах и дюймах.

Таким образом, значения полей объекта класса Distance могут быть заданы дву­мя способами. В функции main() мы определили две переменные типа Distance: distl и dist2. Значения полей для первой из них задаются с помощью функции setdist(), вызванной с аргументами 11 и 6.25, а значения полей переменной dist2 вводятся пользователем. Результат работы программы выглядит следующим образом:

Введите число футов: 10 Введите число дюймов: 4.75

distl = 11’-6.25" - задано аргументами программы distl - 10'-4.75" - введено пользователем

 

Конструкторы

Пример ENGLOBJ демонстрирует два способа использования методов класса для инициализации полей объекта класса. Как правило, удобнее инициализи­ровать поля объекта автоматически в момент его создания, а не явно вызывать в программе соответствующий метод. Такой способ инициализации реализуется с помощью особого метода класса, называемого конструктором. Конструктор — это метод класса, выполняющийся автоматически в момент создания объекта.

Конструкторы класса

При создании объекта автоматически вызывается специальный метод, кото­рый называется конструктором (constructor). У конструктора имя класса и обязательно открытый спецификатор доступа. Конструктор управляет по­строением объекта в оперативной памяти. Процесс построения включает в себя выделение памяти для членов-данных типа указателей, а также ини­циализацию данных.

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

Важно помнить, никакой конструктор не должен делать ничего, что касается обработки членов-данных. За обработку членов-данных несут ответствен­ность не конструкторы, а другие методы в классе.

Пример со счетчиком

В качестве примера мы создадим класс, объекты которого могут быть полезны практически для любой программы. Счетчик — это средство, предназначенное для хранения количественной меры какой-либо изменяющейся величины. Счетчик может хранить число обращений к файлу, число раз, которое пользователь нажал клавишу Enter, или количество клиентов банка. Как правило, при наступ­лении соответствующего события счетчик увеличивается на единицу (инкремен-тируется). Обращение к счетчику происходит, как правило, для того, чтобы уз­нать текущее значение той величины, для измерения которой он предназначен.

Допустим, что счетчик, который мы сейчас создадим, будет важной частью нашей программы, и многие из ее функций будут использовать значение этого счетчика. В процедурных языках, таких, как С, счетчик, скорее всего, был бы представлен в виде глобальной переменной. Но использование глобальных переменных усложняет разработку программы и не­безопасно с точки зрения несанкционированного доступа со стороны функций. Наш следующий пример, COUNTER, использует такой счетчик, значение которого может быть изменено только с помощью его собственных методов.

// counter.срр

// счетчик в качестве объекта

#include <iostream>

using namespace std;

//////////////////////////////////////////////////////////

class Counter

{

private:

unsigned int count;    // значение счетчика

public:

Counter(): count(0)    // конструктор

{ /* пустое тело */ }

void inc_count() // инкрементирование счетчика

  { count++; }

int get_count() // получение значения счетчика

   { return count; }

};

//////////////////////////////////////////////////////////

int main()

{

Counter c1, c2;   // определение с инициализацией

cout <<"\nc1-" << c1.get_count(); // вывод

cout << "\nc2=" << c2.get_count();

c1.inc_count();    // инкрементирование cl

c2.inc_count();    // инкрементирование c2

c2.inc_count();    // инкрементирование c2

cout << "\ncl=" << c1.get_count(); // вывод

cout << "\nc2=" << c2.get_count();

cout << endl;

return 0;

}

Класс Counter имеет единственное поле count типа unsigned int, поскольку значение счетчика не может быть отрицательным, и три метода: конструктор Counter(), который мы рассмотрим чуть позже, inc_count(), инкрементирующий поле count, и get_count(), возвращающий текущее значение счетчика.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: