Классы являются основой С++. Перед тем, как создать объект С++, необходимо определить его общую форму, используя ключевое слово class. Класс определяет новый тип данных, который соединяет в себе код и данные. По синтаксису класс аналогичен структуре. Однако класс также может включать функции, а не только данные. В качестве примера следующий класс определяет тип, который мы называем queue (очередь).
// создание класса очередь
Class queue {
int q[100];
int sloc, rloc;
public:
void init ();
void qput(int i);
int qget();
};
Класс может содержать публичные и частные части. По умолчанию все члены класса являются частными. Например, переменные q, sloc и rloc являются частными, то есть функции, не являющиеся членами класса, не имеют к ним доступа. Именно так достигается инкапсуляция: доступ к определенным частям данных может быть строго контролируемым. Хотя это и не показано в данном примере, можно также определить частные функции, которые могут вызываться только членами данного класса.
Для того, чтобы сделать части класса доступными из других частей программы, они должны быть объявлены с использованием ключевого слова public, которое и служит спецификатором доступа. Все переменные или функции, определенные после ключевого слова public, являются публичными, т.е. доступны для всех других функций в программе. В общем случае доступ к объекту из остальной части программы осуществляется с помощью функций со спецификатором доступа public. Хотя можно иметь переменные с публичным доступом, лучше ограничить их использование или вовсе исключить из употребления. Вместо этого следует сделать все данные частными и контролировать доступ к ним с помощью функций, имеющих спецификатор доступа public. Таким образом публичные функции обеспечивают интерфейс к частным данным класса. Это помогает реализовать инкапсуляцию. Обратим внимание также, что после ключевого слова public следует двоеточие.
Функции init(), qput() и qget() называются функциями-членами, потому что они являются частью класса queue. Переменные sloc, rloc и q называются переменными-членами (или членами данных). Только функции-члены имеют доступ к частным членам класса, в котором они объявлены. Таким образом, только init(), qput() и qget() имеют доступ к sloc, rloc и q.
Как только определен класс, можно создать объект этого типа, используя имя класса. Фактически имя класса становится спецификатором нового типа данных. Например, следующий код создает объект с именем intqueue типа queue:
queue intqueue;
Также можно создать объекты при определении класса, помещая имена переменных после закрывающей фигурной скобки, в точности так же, как это имеет место для структуры. Общий вид объявления класса следующий:
class имя_класса {
private данные и функции
public:
публичные данные и функции
} список объектов;
Разумеется, список объектов может быть пустым.
Внутри объявления класса queue использовались прототипы функции. Когда необходимо сообщить компилятору о функции, то следует использовать полную форму прототипа. Более того, в С++ все функции должны иметь прототипы. Прототипы не являются факультативными, как это было в С.
Когда приходит очередь написать реальный код функции-члена, необходимо указать компилятору, какому именно классу принадлежит эта функция. Например, ниже показан один из способов написания функции qput():
void queue::qput(int i)
{
if (sloc==99) {
cout << "Queue is full.\n";
return;
}
sIoc++;
q[sloc] = i;
}
Последовательность символов :: называется оператором области видимости (scope resolution operator). Он показывает принадлежность функции классу. В данном случае он говорит компилятору, что данная версия функции qput() принадлежит классу queue. Другими словами, функция qput() находится в области видимости класса queue. В С++ несколько различных классов могут использовать одинаковые имена функций. Компилятор знает, какая из них принадлежит какому классу благодаря оператору области видимости и имени класса.
Если вы рассматриваете часть программы, которая не входит в состав класса, то для вызова функции-члена класса необходимо использовать имя объекта и оператор «точка». Например, следующий фрагмент иллюстрирует вызов функции init() для объекта а:
queue a, b;
а.init();
Очень важно ясно себе представлять, что а и b являются двумя различными объектами. Это означает, что инициализация а не означает инициализацию b. Единственной связью между объектами а и b служит то, что они являются объектами одного и того же типа. Более того, копии переменных sloc, rloc и q объекта а совершенно независимы от соответствующих копий переменных объекта b.
Использование имени класса и оператора «точка» необходимо только при вызове функции-члена извне класса. Внутри класса одна функция-член может вызывать другую функцию-член непосредственно без использования оператора «точка». Аналогично функция-член может обращаться непосредственно к переменной-члену без использования оператора «точка». Представленная ниже программа демонстрирует все части класса queue:
#include <iostream.h>
// создание класса очередь
class queue {
int q[100];
int sloc, rloc;
public:
void init ();
void qput(int i);
int qget();
};
void queue::init ()
{
rloc = sloc = 0;
}
void queue::qput(int i)
{
if (sloc==99) {
cout << "Queue is full.\n";
return;
}
sIoc++ ; q[sloc] = i;
}
int queue::qget ()
{
if (rloc == sloc) {
cout << "Queue underflow.\n";
return 0;
}
rloc++;
return q[rloc];
}
int main ()
{
queue a, b; // создание двух объектов типа queue
а.init();
b.init();
a.qput(10);
b.qput(19);
a.qput(20);
b.qput(1);
cout << a.qget()<< " ";
cout << a.qget()<< " ";
cout << b.qget()<< " ";
cout << b.qget()<< "\n";
return 0;
}
Следует запомнить, что частные части объекта доступны только для функций, которые являются членами объекта. Например, следующая строка кода
a.rloc = 0;
не может находиться в функции main() предыдущей программы, потому что rloc является частным членом.
ЗАМЕТКА: Согласно существующему соглашению, в большинстве программ на языке С функция main() является первой функцией программы. Однако в программе queue функции члены класса queue определены раньше функции main(). Такой подход является обычным при написании программ на языке C++. |