- •2 Программирование классов
- •Void Display(struct tTime tp)
- •Int year; //Данные-//члены
- •Int month; // -//-
- •Int hour; // -//-
- •Int minute; // -//-
- •Void Display(void); // Функция-// член
- •7: Int month; // “ “
- •9: Int hour; // “ “
- •10: Int minute; // “ “
- •3: #Ifndef time1_h
- •4: #Define time1_h 1
- •21: #Endif // _ _time1_h
- •Замечание
- •Типы доступа
- •Объект класса выходит
- •Объект конструктор требуемое количество функции-члены вызывается деструктор
- •Выделенную память
из
области видимости
Создается
С++ вызывает конструктор выделяет
программа вызывает или удаляется
.С++
Класса
класса объекта памяти
класса
который освобождает
0
t+1 t+2
t+3
t+n
Объект класса выходит
Объект конструктор требуемое количество функции-члены вызывается деструктор
Выделенную память
Рис. 2.5. события, обычно происходящие с объектами во время его существования
Глобальные объекты класса
Конструктор глобальных объектов класса вызывается до начала выполнения функции main().
Это обеспечивает инициализации всех глобальных объектов до формального начала выполнение программы.
ПРИМЕР:
При использовании классаTTime (листинг 2.18 и 2.19) глобальное объявление
TTime today;
Создает глобальный объект today класса TTime. До вызова main() C++ вызывает для today конструктор TTime по умолчанию, который устанавливает в объекте текущую дату и время.
Для инициализации глобального объекта класса TTime каким-либо определенным датой и времени следует использовать следующее объявление:
TTime sTime(9, 4, 1953, 10, 45);
Наличие списка инициализаторов в круглых скобках С++ вызовет перегруженный конструктор TTime (строки 17-18 листинга 2.18), который инициализирует stime значением даты и времени 4 сентября 1953 года, 10:45.
это действие выполнится до того, как будет вызвана main().
Деструкторы глобальных объектов класса вызываются как обычно в качестве части кода завершения программы, после отработки функций завершения, заданных вызовами функции exit(). Деструкторы не вызываются, если программа заканчивается с помощью обращения к abort().
Локальные объекта класса
Автоматические объекты класса, объявленные локальными в функции, создаются вместе с вызовом функции и уничтожается с ее завершением.
Как и переменных обычных типов, данные-члены автоматического объекта класса сохраняются в стеке.
В функции
void anyFunction(void)
{
TTime now;
// Инициализируется при каждом //вхождении в функцию
….
}
по умолчанию вызывается конструктор TTime для инициализации объекта класса now текущими датой и временем каждый раз, когда вызывается функция.
Когда функция завершает работу, С++ вызывает деструктор TTime для объекта now.
(что дает объекту возможность “убрать” за собой до того, как он выйдет из видимости.)
При вызове exit() деструкторы глобальных объектов классов вызывается как обычно, а деструкторы любых существующих автоматических переменных, локальных в функции (включая и те, которые локальны в main()), не вызываются.
Указатель на объекты
Указатели могут ссылаться на динамические объекты класса, пространство для которых обычно выделяется в куче с помощью new.
ПРИМЕР:
// указатель pToday на объект класса //типа TTime
TTime *pToday;
Это объявление м.б. как глобальным в функции.
// инициализация указателя pToday до
//его использования с помощью new
pToday = new TTime;
// с помощью оператора new выделяется пространство в куче для объекта типа TTime.
Адрес первого байта этого объекта присваивается pToday.
С++ вызывает конструктор объекта по умолчанию, который инициализирует объекта текущими датой и временем.
Для использования другого конструктора добавьте параметры после имени класса.
для выделения памяти для объекта TTime и инициализации его с помощью вызова конструктора с пятью параметрами :
pToday=new Time(9, 4, 1953, 10,45);
использование указателей на объекты класса для ссылки на член адресуемого объекта можно
с помощью оператора ->
оператора *
Указатели на объекты класса используются в точности так же, как и указатели на объекты других типов.
Пример:
//вывод даты и времени объекта класса
//TTime, на который ссылается pToday:
pToday->Display();
Пример:
Sp = ( *pToday).GetSTime();
//присваивание переменной sp (которая //объявлена, как const char *sp;) результата функции-//члена GetSTime() для объекта //класса, на который ссылается //pToday.
Sp = pToday->GetSTime();
//легче,выполняется аналогично .
С++ вызывает деструкторы динамических объектов класса при их удалении. Пример:
delete pToday;
//удаление объекта, на который //ссылается pToday, освобождение //памяти этого объекта в куче.
//перед разрушением объекта С++ //вызывает деструктор класса.
Не путайте жизнь указателя с жизнью объекта, на который он ссылается. Глобальный указатель существует до тех пор, пока программа не завершится, но он может ссылаться на множество объектов класса, создаваемых с помощью new и удаляемых с помощью delete. Аналогично, автоматически указатели, объявленные локальными в функции, создаются при выполнении функции и уничтожаются при ее завершении. Но объекты, на которые ссылаются указатели, имеют глобальную область действия и должны удалятся явным образом.
В функции f(), если вы вызовете new для создания объекта в куче, этот объект останется в памяти даже после завершения функции. Вы должны явным образом удалять любой подобный объект, если вы не хотите, чтобы он оставался в памяти после возврата из функции.
Ссылочные объекты
Обычно ссылки объявляются в качестве параметров функции. На практике они редко используются так, как описано в этом разделе.
Объекты класса могут объявляться как ссылки. Предположим, вы объявили глобальный объект класса TTime:
TTime today;
// глобальный объект today
Позже, в программе, вы можете объявить ссылку на today следующим образом:
TTime &rToday = today ;
// ссылка на today
Ссылка rToday – алиас для today, и можете использоваться вместо today. Например, каждый из следующих двух операторов выведет дату и время:
rToday.Display();
today.Display();
Поскольку ссылки ссылаются на реально существующие объекты, при входе в область действия ссылки конструктор класса не вызывается и, соответственно, не вызывается деструктор при выходе из области действия ссылки. Эти действия выполняются только при создании и удалении самого объекта.
Совет
Обычно ссылки объявляются в качестве параметров функции. На практике они редко используются так, как описано в этом разделе.
Объекты-параметры
можно передавать объекты класса, указатели на объекты класса и ссылки на них в качестве аргументов функций.
Классы это типы данных, и вы можете объявлять параметры функции, имеющие тип классов так же, как и параметры других типов.
1. Пример передачи по значению:
//реализация ф-ции
void anyFunction(TTime t)
// параметр t типа TTime
{
t.Display();
//вызывается функция-член Display() объекта t для вывода даты и //времени, хранящихся в параметре
}
пример:
//вызов ф-ции
// объявление объекта класса TTime
TTime today;
anyFunction(today);
Функции также могут объявлять в качестве параметров указатели на класс.
Передача больших по размерам объектов класса функции по значению приводит к выделению пространства нежелательной величины в стеке для таких объектов.
В таких случаях предпочтительней параметры-указатели.
2. Пример передачи с параметрами-указателями:
void anyFunction(TTime *tp)
{
tp->Display();
}
вызов этой ф-ции
anyFunction(&today);
3. Пример передачи с с использованием ссылочного параметра (на объект класса TTime):
void anyFunction(TTime &tr) // tr—ссылочный параметр
{
tr.Display();
// вызов Display() для объекта, на //который ссылается tr
// передача объекта класса TTime
//в качестве ссылочного параметра
anyFunction(today);
недостаток ссылочных параметров – такой оператор похож на передачу аргумента today по назначению.
Факт передачи в anyFunction() ссылки на today из текста совершенно не очевиден.
Объекты результаты функций
Функции могут возвращать объекты классов непосредственно в качестве указателей или как ссылки.
1.Пример: функция, возвращает объект класса TTime
TTime newTime(void)
{
// Локальный объект t (автоматически инициализированный вызовом конструктора в начале выполнения функции) возвращается непосредственно.
TTime t;
return t;
}
//вызов ф-ции
// результат функции newTime() //копируется в anTime
TTime anTime = newTime();
Такой подход имеет мало преимуществ
2.Пример: функция, возвращает указатели на объекты класса
TTime *newTimeP(void)
{
TTime *P = new TTime;
// выделение и инициализация //объекта
return P;
// возвращение адреса объекта в //качестве результата функции
//объект, на который ссылается этот //указатель, глобальный, сл-но можно вернуть указтель
}
//вызов ф-ции
TTime *tp =newTimeP();
//получение нового объекта и //присвоение его адреса указателю tp
3.Пример: функция, возвращает ссылки на объекты класса
//ссылочная функция для ссылки на //существующий глобальный объект //Ttimetoday:
TTime &newTimeR(void)
{
return today;
}
//вызов ф-ции
…
//объявление ссылки на TTime
//присвоение ей результата //newTimeR()
TTime &tr = newTimeR();
//ccылка tr— псевдоним для today
…
newTime R().Display();
Это полезно в случае, если функция подобная newTimeR(), выполняет операцию поиска с возможным возвратом ссылки на один из нескольких объектов класса TTime, исходя из неких указанных критериев.
Массивы объектов класса
Пример: массив из 10 элементов объектов TTime
TTime tenTimes[10];
//С++ вызывает 10 раз конструктор по умолчанию TTime, //инициализируя таким образом объекты tenTimes[0]tenTimes[9] //текущими датой и временем
строгое правило: объекты класса, Которые, будут содержать массив, должны иметь конструкторы по умолчанию.
Пример 2.22 OB.CPP (массивы и конструкторы по умолчанию)
(используется класс TTime, определенный ранее в TIME6.H)
1: #include <iostream.h>
2: #include <stdio.h>
3: #include “time6.h”
4:
5: main()
6: {
//объявляется массив tar из
//шести объектов TTime
7: TTime tar[6];
8:
9: for (int i = 0; i < 6; i++)
// шесть одинаковых дат и времен
10: tar[i].Display();
11: return 0;
12: }
Для вызова различных конструкторов, надо явным образом инициализировать каждый элемент массива.
Пример 2.23 OB1.CPP (объявление массивов и альтернативных конструкторов)
1: #include <iostream.h>
2: #include <stdio.h>
3: #include “time6.h”
4:
5: main()
6: {
//объекты массива
//инициализируются конструкторами,
//указателями в скобках
7: TTime tar[6] = {
// с помощью вызова конструктора по //умолчанию
8: TTime(),
//вызов перегруженных
// конструкторов
9: TTime(8),
10: TTime(8, 1),
11: TTime(8, 1, 1996),
12: TTime(8, 1, 1996, 8 ),
13: TTime(8, 1, 1996, 8, 30),
14: };
15: for (int i = 0; i < 6; i++)
16: tar[i].Display();
17: return 0;
18: }
Нет простого способа инициализировать одни массивы объектов класса с помощью конструктора по умолчанию, а другие с помощью альтернативного конструктора.
Этот прием слишком громоздкий для широкого применения на практике за исключением небольших по размеру массивов.
Массивы объектов классов могут также размещаться в куче и адресоваться с помощью указателей.
Пример 2.24. OB3.CPP (поддержка динамических массивов объектов класса)
1: #include <iostream.h>
2: #include <stdio.h>
3: #include “time6.h”
4:
5: main()
6: {
// tarP - указатель на объект класса //TTime
7: TTime *tarP;
8:
9: tarP = new TTime[6];
// Создание динамического массива
10: for (int i = 0; i < 6; i++)
11: tarP[i].Display();
12: delete[] tarP;
// особая форма delete[]
//вызов всех деструкторов (для //каждого объекта в массиве) при
//удалении динамического массива
// объектов класса
13: return 0;
14: }
Замечание
В прошлых версиях С++ необходимо было указывать число элементов вудаляемом массиве объектов класса и вам пришлось бы использовать операторы вида delete[6] tarrayP; для удаления массива из шести объектов класса TTime, на который ссылается tarrayP. Применение этого приема ныне не допускается, и Borland С++ игнорирует любые значения внутри скобок delete[]. Если вы укажете размер массива в скобках, компилятор выдаст вам предупреждение “array size for ‘delete” ignored in function x() ” (Размер массива для delete проигнорирован в функции x()).
**************************************************************
ИТОГИ
Элементы –поля и методы класса.
Поля – данные класса (данные-члены).
Методы – функции класса (ф-ции члены).
сlass <bvz> {
[private:]
<описание скрытых эл-тов >
Public:
<описание доступных эл-тов >
};
Поля класса:
м.б.любого типа;
м.б. описаны с модификатором const, инициализируются один раз (конструктором) и не м. изменяться;
м.б. описаны с модификатором static ( не auto, extern, register).
Static-статическая переменная. Время жизни – постоянное. Инициализация – один раз при первом выполнении оператора, инициализирующего переменную. М.б. лок. , глоб.
Auto- автоматическая переменная. Память выделяется в стеке, инициализация – столько раз, сколько нужно. Освобождение – при выходе из блока. Время жизни : от начала описания до конца блока. Для лок-ных – по умолчанию, для глоб. – не исп-ся.
Extern- переменная объявлена в другом месте программы (др. модуль, или дальше в программе). Исп-ся для создания пер-ных, доступных во всех модулях.
Register- аналог Auto. Память выделяется в регистрах процессора
ОПИСАНИЕ ОБЪЕКТОВ
Конкретные переменные типа «класс» называются экземплярами класса, или объектами. Время жизни и видимость объектов зависят от вида и места их описания и подчиняются общим правилам C++:
TTime V; // Объект класса TTime с параметрами по
TTime Super(200, 300); // Объект с явной инициализацией TTime stado[100]: // Массив объектов с параметрами по
TTime *beavis = new monstr (10); // Динамический объект
//(второй параметр задается по умолчанию
TTime &butthead = V;
// Ссылка на объект
При создании каждого объекта выделяется память, достаточная для хранения всех его полей, и автоматически вызывается конструктор, выполняющий их инициализацию. Методы класса не тиражируются. При выходе объекта из области действия он уничтожается, при этом автоматически вызывается деструктор.
Дocmyn к элементам объекта аналогичен доступу к полям структуры. Для этого используются операция . (точка) при обращении к элементу через имя объекта и операция -> при обращении через указатель, например:
int n = V.get();
stado[5].draw;
cout « beavis->get();
Обратиться таким образом можно только к элементам со спецификатором publiс. Получить или изменить значения элементов со спецификатором private можно только через обращение к соответствующим методам.
Можно создать константный объект, значения полей которого изменять запрещается. К нему должны применяться только константные методы:
class monstr{
int get_h() const {return h:}
}:
const monstr D(0,0);
// Константный объект
cout « D.get_h():
Константный метод:
объявляется с ключевым словом const после списка параметров;
не может изменять значения полей класса;
может вызывать только константные методы;
может вызываться для любых (не только константных) объектов.
Рекомендуется описывать как константные те методы, которые предназначены для получения значений полей.
Указатель this
Каждый объект содержит свой экземпляр полей класса.
Методы класса находятся в памяти в единственном экземпляре и используются всеми объектами совместно, поэтому необходимо обеспечить работу методов с полями именно того объекта, для которого они были вызваны. Это обеспечивается передачей в функцию скрытого параметра this, в котором хранится константный указатель на вызвавший функцию объект.
Указатель this неявно используется внутри метода для ссылок на элементы объекта.
В явном виде этот указатель применяется в основном для возвращения из метода указателя (return this;) или ссылки (return *this;) на вызвавший объект.
Для иллюстрации использования указателя this добавим в приведенный выше класс monstr новый метод, возвращающий ссылку на наиболее здорового (поле health) из двух монстров, один из которых вызывает метод, а другой передается ему в качестве параметра (метод нужно поместить в секцию public описания класса):
Monstr & thebest(monstr &M){
1f( health > М.health) return *this; return M;
... monstr V(50), Super(200);
// Новый объект Best инициализируется значениями полей Super:
monstr Best = V.the_best(Super);
Указатель this можно также применять для идентификации поля класса в том случае, когда его имя совпадает с именем формального параметра метода.
Другой способ идентификации поля использует операцию доступа к области видимости:
void cur(int h,int am){
this -> h += h;
// Использование this
monstr:: am += am;
// Использование операции ::
Конструкторы
Конструктор предназначен для инициализации объекта и вызывается автоматически при его создании.
основные свойства конструкторов.
Конструктор не возвращает значение, даже типа void.
Нельзя получить указатель на конструктор.
Класс может иметь несколько конструкторов с разными параметрами для разных видов инициализации (при этом используется механизм перегрузки).
Конструктор, вызываемый без параметров, называется конструктором по умолчанию.
Параметры конструктора могут иметь любой тип, кроме этого же класса. Можно задавать значения параметров по умолчанию. Их может содержать только один из конструкторов.
Если программист не указал ни одного конструктора, компилятор создает его автоматически. Такой конструктор вызывает конструкторы по умолчанию для полей класса и конструкторы по умолчанию базовых классов. В случае, когда класс содержит константы или ссылки, при попытке создания объекта класса будет выдана ошибка, поскольку их необходимо инициализировать конкретными значениями, а конструктор по умолчанию этого делать не умеет.
Конструкторы не наследуются.
Конструкторы нельзя описывать с модификаторами const, virtual и static.
Конструкторы глобальных объектов вызываются до вызова функции main Локальные объекты создаются, как только становится активной область их действия. Конструктор запускается и при создании временного объекта (на пример, при передаче объекта из функции).
Конструктор вызывается, если в программе встретилась какая-либо из синтаксических конструкций:
имя_класса имя_объекта [(список параметров)];
// Список параметров не должен быть пустым
имя_класса (список параметров);
//созд. Объект без имени
Имя_класса имя_объекта=выр-ние;
//создается объект без имени и копируется
СТАТИЧЕСКИЕ ЭЛЕМЕНТЫ КЛАССА
Статические поля
Статические поля применяются для хранения данных, общих для всех объектов класса, например, количества объектов или ссылки на разделяемый всеми объектами ресурс. Эти поля существуют для всех объектов класса в единственном экземпляре, то есть не дублируются.
особенности статических полей.
□ Память под статическое поле выделяется один раз при его инициализации независимо от числа созданных объектов (и даже при их отсутствии) и инициализируется с помощью операции доступа к области действия, а не операции выбора (определение должно быть записано вне функций):
class A{ public:
static int count;
// Объявление в классе
int A::count;
// Определение в глобальной области
// По умолчанию инициализируется нулем
int Account = 10;
// Пример инициализации произвольным значением
□ Статические поля доступны как через имя класса, так и через имя объекта:
А *а, b;
cout « Account « a->count « b.count;
// Будет выведено одно и то же
На статические поля распространяется действие спецификаторов доступа, поэтому статические поля, описанные как private, нельзя изменить с помощью операции доступа к области действия, как описано выше. Это можно сделать только с помощью статических методов .
Память, занимаемая статическим полем, не учитывается при определении размера объекта с помощью операции sizeof.
Статические методы
Статические методы предназначены для обращения к статическим полям класса. Они могут обращаться непосредственно только к статическим полям и вызывать только другие статические методы класса, потому что им не передается скрытый указатель this. Обращение к статическим методам производится так же, как к статическим полям — либо через имя класса, либо, если хотя бы один объект класса уже создан, через имя объекта.
class A{
static int count;
// Поле count - скрытое public:
static void inc_count(){ count++: }
…
А::int count; // Определение в глобальной области void f(){
А а;
// a.count++ - нельзя, поле count скрытое
// Изменение поля с помощью статического метода:
a.inc_count(); // или A::inc_count();
Статические методы не могут быть константными (const) и виртуальными (virtual).