Читайте также:
|
|
Классы могут быть глобальными (определенными вне любого блока) и локальными (определенными внутри блока).
Особенности локальных классов:
Замечание. Объект, который перегружает операцию вызова функции ( operator() ), часто называется функтором. Функторы, обычно, используются со стандартными алгоритмами для лучшей инкапсуляции функциональности (т.е., выполняемых функций).
· Если один класс вложен (nesnted: имя вложенного класса локально по отношениюк внешнему классу) в другой, то внутренний класс не имеет каких-либо привилегий доступа к внешнему классу, и наоборот. Вложенный класс может быть объявлен внутри определения своего внешнего класса, а позже определен в текущем пространстве имен (области действия). В этом случае, вложенное имя должно быть квалифицировано (дополнено) именем внешнего класса. Часто вложенные классы полностью определяются внутри внешних классов.
Использование локальных классов не распространено.
Пример для вложенных классов на примере структур:
struct outer { struct inner1 { int foo() { return 10; } }; class inner2;}; struct outer::inner2 { int foo();}; int outer::inner2::foo() { outer::inner2 x; return x.foo();} Пример использования простого класса: #include <iostream.h> class CRectangle { int x, y; public: void set_values (int,int); int area (void) {return (x*y);}};void CRectangle::set_values (int a, int b) { x = a; y = b;} int main () { CRectangle rect; rect.set_values (3,4); cout << "area: " << rect.area();}
Очень кратко упомянем об одном из важнейших для ООП свойств механизма классов в С++: наследовании классов. Детальное обсуждение этой темы будет приведено позже.
Один класс может наследовать характеристики другого класса. Обычно, наследуемый класс называется базовым классом, а класс-наследник – производным классом. Когда один класс наследует другой, то возникает иерархия классов. Общая форма синтаксиса для описания производного класса (неформально) выглядит так:
class имя-класса: доступ имя-базового класса {
//...
};
Здесь, доступ(спецификатор доступа) определяется как private, public, или protected. (Вид доступа может быть опущен, и тогда, если предполагается, что производный класс – структура, то по умолчанию доступ public, а в случае, если наследник является классом, доступ по умолчанию - private). При наличии нескольких “родителей” они перечисляются списком через запятую, и говорят о множественном наследовании.
Если доступ есть public, все public - и protected - членыбазового класса становятся public - и protected - членами производного класса, соответственно. Если доступ - private, то все public - и protected - члены базового класса становятся private - членами производного класса. Если доступ объявлен как protected, все public - и protected - члены базового класса становятся protected - членами производного класса.
В следующей иерархии классов класс Derived наследует класс Base как закрытый (private). Это означает, что поле i становится закрытым членом производного класса Derived.
class Base {public: int i;};class Derived: private Base { int j;public: Derived(int a) { j = i = a; } int getj() { return j; } int geti() { return i; } // OK, здесь Derived имеет доступ к i}; Derived ob(9); // создаем объект класса Derivedcout << ob.geti() << " " << ob.getj(); // OK// ob.i = 10; //ОШИБКА!, i закрыт для Derived; доступ только через geti
Ниже мы приводим еще один пример использования классов в программе. Эта программа имитирует цифровой таймер. Таймер отображает минуты и секунды. Пользователю должна быть предоставлена возможность установки времени и отображение его на экране. Когда таймер запускается – звенит “колокольчик”.
Хотя небольшие программы могут быть написаны в виде одного файла, мы, для иллюстрации раздельной компиляции, разбили программу на три файла:
Первый файл назван " timer.h " – содержит интерфейс класса с именем Timer. Это заголовочный файл, который нужно включить в другие файлы.
Второй файл, названный " timer.cpp ", содержит детальную реализацию функций класса. В этот файл нужно включить директивой #include файл timer.h.
Третий файл – тестовая программа timer_app.cpp. В этот файл также включен заголовок timer.h.
// Файл "timer.h"
class Timer
{
private:
// два поля
int sec; // число оставшихся секунд
int min; // число оставшихся минут
// две закрытые функции
void show() const; // представляет оставшиеся минуты и секунды
void decrement(); // уменьшает оставшееся время на 1 сек.
public:
// три открытые функции
Timer() { }; // конструктор
void set(); // установить таймер
void run(); // запустить таймер
};
Объяснение.
(i) Макет (синтаксис) объявления класса:
(a) Объявление класса начинается служебным (зарезервированным) словом class. Имя класса мы написали с заглавной буквы, но это - по желанию. Например, в VC принято имена классов начинать с заглавной буквы C (CDoc, CView и т.п.), у фирмы Borland – c буквы T. Ключевые слова public и private указывают, что следующие за ними члены принадлежат секции с соответствующим видом доступа к членам. Как мы уже говорили, если член не принадлежит никакой специфицированной секции, то он, по умолчанию, отнесен к private. Действие спецификатора доступа распространяется до следующего спецификатора или до конца класса.
(b) Функции члены доступны из любого места внутри определения класса. Порядок их указания – не существенен.
(c) Поскольку функции show() и decrement() используются только внутри класса, то они объявлены в private -секции.
(d) Доступ к членам класса выполняется с помощью селектора “точка”(.), как для структур. Например, если x – объект класса Timer, то x.min – обращение к полю min. Если p – указатель на объект Timer, то p->min или p->show() – доступ к соответствующим членам.
(ii) Конструкторы:
Конструктор – это функция, которая (обычно) вызывается автоматически при создании объекта. Конструктор не имеет возвращаемого типа, но может принимать параметры для инициализации полей создаваемого объекта. Конструктор можно перегружать. Подробнее о перегрузке конструкторов мы поговорим позже.
Конструктор без параметров (но могут быть параметры по умолчанию) называют конструктором по умолчанию (default constructor). Класс может иметь любое число конструкторов (перегруженных), которые отличаются друг от друга списками параметров.
В классе должен быть по меньшей мере один конструктор. Если никакого конструктора явно не объявлено, то компилятор обеспечивает класс конструктором по умолчанию, который не выполняет инициализации каких-либо полей класса. (Поэтому, в нашем примере конструктор по умолчанию не объявлен). Бывает, что конструктор по умолчанию от компилятора работает иначе, чем явно объявленный, Всегда явно определять конструктор по умолчанию – хорошая практика, если только не существует особой причины чтобы этого не делать. Если конструктор (любого вида) объявлен в классе, то компилятор не поставляет свой конструктор по умолчанию, и, в этом случае, если конструктор с параметрами для инициализации, то всякий создаваемый объект такого класса должен объявляться с начальными значениями (если они вообще нужны)
В нашем классе конструктор определен внутри объявления класса. Функции-члены, определенные внутри класса, по умолчанию, являются встроенными. Если функция слишком сложная (это зависит от компилятора), чтобы быть inline -функцией, то она должна быть определена отдельно, вне объявления класса (с использованием квалифицированного имени).
// файл "timer.cpp"
#include <iostream.h>
#include <time.h> // стандартный заголовочный файл
#include "timer.h"
#define STOP ((min == 0)&&(sec == 0))
// таймер останавливается, когда остается 0 минут и 0 секунд
// показывает оставшееся время в формате mm:ss
inline void Timer::show() const
{
// вывод минут – две цифры
(min < 10)?(cout << "0" << min):(cout << min);
cout << ":";
// вывод секунд – две цифры
(sec < 10)?(cout << "0" << sec):(cout << sec);
cout << endl;
}
// уменьшает время на 1 сек.
void Timer::decrement()
{
if (!STOP)
{ (sec!= 0)?--sec:(sec = 59,--min); }
}
void Timer::set()
{
cout << "Введите время для установки таймера ";
cout << " в формате mm ss\n";
cin >> min >> sec;
cout << "Вы установили время работы таймера в течение" << min << " минут и "
<< sec << " секунды.\n";
}
void Timer::run()
{
time_t * tptr = new time_t;
// не забудьте выделить память по указателю на тип time_t
time_t t;
while (!STOP)
{
t = time(tptr);
// опрос текущего времени с помощью функции time(), определенной в <time.h>
while (t == time(tptr)); // без тела
// выборка времени из внутренних часов, пока их “показание” не изменяется
decrement();
show();
}
cout << "\a"; // вывод звонка тревоги
delete tptr;
return;
}
Объяснение:
(i) Имя функции-члена определено вне объявления класса и следует за именем класса и операцией ::, т.е., является квалифицированным именем.
(ii) Функции-члены (show() и decrement()) нашего класса принадлежат индивидуальным объектам-таймерам. Указатель на объект, для которого вызывается метод, неявно передается функции как первый параметр. Этот указатель обозначается служебным словом this (Мы посмотрим на явное применение указателя 'this' позже). Поэтому, данные-члены, такие как min и sec в функциях show() и decrement(), на самом деле, являются выражениями this -> min и this -> sec, а функции show() и decrement(), вызываемые внутри функции run() есть this -> show() и this -> decrement(), но мы можем использовать упрощенную форму, опустив часть "this ->".
(iii) Если функция-член специфицирована как константная (constant member function), как наша функция show(), тогда указатель "this", передаваемый этой функции есть указатель на константу(!), т.е., объект, для которого вызвана функция, не может быть модифицирован этой функцией. Мы можем передать неконстантный объект константной функции, но не можем передать константный объект неконстантному методу. (Разные компиляторы реагируют, иногда, на это по-разному: одни предупреждают, другие – фиксируют ошибку).
Заметим, что теперь мы знаем три способа использования модификатора const при объявлении прототипов функций:
const int& func(int); // функция возвращает константную ссылку на int
int func(const int&); // функция принимает константную ссылку на int как параметр
int func(int) const; // здесь функция – метод класса,
// для нее объект *this есть константный объект
// т.е. здесь this – конст. указатель на константу.
(iv) time_t является типом, зависящего от реализации, закодированного значения текущего времени на внутренних часах компьютера. Функция time() объявлена в заголовочном файле <time.h>. Эта функция принимает указатель на time_t, и возвращает закодированное время. Это время также присваивается переменной, на которую параметр-указатель указывает (и которая заблаговременно должна быть проинициализирована).
// Файл "timer_app.cpp"
#include <iostream.h>
#include <conio.h> // для использования функции getch()
#include "timer.h"
int main()
{
Timer x;
cout << "Пожалуйста, установите время.\n";
x.set();
cout << "”\Press any key”\ - для старта.\n";
getch(); // ожидать нажатия любой клавиши
x.run();
return 0;
}
Объяснение.
(i) Эта программа определяет объект x класса Timer, x создается конструктором по умолчанию.
(ii) Заметим, что в функции main() мы использовали только открытые методы класса.
+++++++++………..+++++++++
Дата добавления: 2015-11-16; просмотров: 53 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Внимательно ознакомьтесь с ПАМЯТКОЙ МИД России «Каждому, кто направляется за границу». | | | Дружественные классы и дружественные функции (friend). |