Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lek_2_slaydy.doc
Скачиваний:
1
Добавлен:
17.11.2019
Размер:
449.54 Кб
Скачать

Типы доступа

Член класса может иметь следующие модификаторы доступа:

  • public - общедоступный член класса;

  • protected - доступный только для членов и объектов данного класса и наследуемых классов (наследуемых с модификаторами доступа public или protected);

  • private - защищенный метод, доступный только внутри класса.

Встраиваемые функции –члены

использование функции–членов для доступа к данным-членам класса вырабатывает верное отношение к эффективности.

Вызов функции-члена, подобно SetTime(), для присваивания значений данным членам класса занимает больше времени, чем простое присваивание значений непосредственно этим членам, конечно, если он открыт для доступа.

Но одно из основных достоинств класса заключается в запрещении доступа к данным, что упрощает поддержку.

В большинстве случаев вызовы функций-членов вместо прямого доступа к данным-членам заметно сказываются на быстродействии программы.

С++ позволяет объявлять классы с встраиваемыми функциями-членами. Хотя, встраиваемые функции-члены используются точно так же, как и другие функции, в скомпилированном коде они не вызываются. Вместо этого встраиваемые функции – члены вставляются непосредственно в скомпилированную программу (рис. 2.3)

Рис.2.3. Встраиваемые функции-члены вставляются непосредственно в программный код

Листинг 2.9 заново объявляет класс TTime с использованием нескольких встраиваемых функций-членов (строки 14 и 17-22).

Листинг 2.9. (новое объявление касса TTime с встроенными функциями членами )

1:// time3.h –Объявление класса TTime

2:

3: #ifndef_ _ TIME3_H

4: #define _ _TIME3_H 1

// Предотвращение нескольких

// #include

5:

6: #include<iostream.h>

7: #include <time. h>

8: #include<string.h>

9:

10: class Ttime {

11: private:

12: long dt; // Дата и время – в //секундах от января 1970 года

13: public:

//встроенная функция-член

14: void Display(void) { cout << ctime(&dt); }

15: void GetTime(int &m, int &d, int &y, int &hr, int &min);

16: void SetTime(int m, int d, int y, int hr, int min);

//встроенная функция-член

17: char *GetTime(void)

18: {

// ctime() для преобразования даты и времени в строку ASCII

19: char *cp = strdup( ctime(dt));

20: return cp;

21: }

22: void ChangeTime(long nminutes) {dt += (nminutes * 60); }

23: };

24:

25: #endif // _TIME3_H

Листинг 2.10. Time3.CPP (реализация невстраиваемых функций класса TTime)

1://time3.cpp-Реализация класса Ttime

2:

3: #include <dos.h>

4: #include “time3.h”

5:

6: // Возвращает текущие данные – члены дату и время

7: void TTime : : GetTime(int &m, int &d, int &y, int &hr, int &hr, int &min)

8: {

9: struct date ds;

10: struct time ts;

11:

12: unixtodos(dt, &ds, &ts)

13: y = ds.da_year;

14: m = ds.da_mon;

15: d = ds.da_day;

16: hr = ts.ti_hour;

17: min = ts.ti_min;

18: }

19:

20: // Устанавливает член dt

21: void TTime : : SetTime(int m, int d, int y, int hr, int min)

22: {

23: struct date ds;

24: struct time ts;

25:

26: ds.da_year = y;

27: ds.da_mon = m;

28: ds.da_day = d;

29: ts.ti_hour = hr;

30: ts.ti_min = min;

31: ts.ti_sec = 0;

32: ts.ti_hund = 0;

33: dt = dostounix(&ds, &ts);

34: }

Поскольку использование встраиваемых функций-членов не отличается от использования обычных функции членов, основная программа осталась без изменений.

Листинг 2.11 идентичен APPOINT2.CPP за исключением того, что в строке3 теперь включается заголовочный фай TIME3.H.

Листинг 2.11. APPOINT3.CPP (отображение примера календаря встреч)

1: #include <iostream.h>

2: #include <stdio.h>

3: #include “time3.h”

4:

5: main()

6: {

7: Ttime appointment;

8:

9:appointment.SetTime(7,21,1996,8,30);

10: for (int slots = 1; slots <= 17; slots++) {

11: appointment. Display();

12: appointment. ChangeTime(30);

13: }

14: return 0;

15: }

Как и в случае с обычными встроенными функциями, С++ может и не вставить функцию-член непосредственно в скомпилированный код. Например, если встраиваемая функция-член слишком сложна, компилятор может решить скомпилировать ее как обычную функцию-член.

Большинство функций-членов объявляются непосредственно в классе, как это показано в строке 14 листинга 2.9. вы можете объявить встраиваемую функцию-член с помощью ключевого слова inline в модуле реализации класса.

Например, для преобразования GetTime()из Ttime во встраиваемую функцию, вы можете изменить реализацию функции в листинге 2.10 следующим образом:

inline void TTime::GetTime(int &m, int &d, int &y, int &hr, int &min)

{

}

поставив inline пред именем функции, можно и не добиться желаемого результата, поскольку реализация встраиваемых функций-членов должна быть доступна компилятору до того, как эта функция будет вызвана. В большинстве случаев встраиваемые функции-члены лучше всего распознаются, когда они объявлены непосредственно в классе.

Перегруженные функции-члены

Перегруженные функции-члены особенно полезны, когда необходимо несколько параметров (а не все) функции-члена.

Например, в текущей функции SetTime() класса TTime необходимо пять параметров. Для того, чтобы установить дату и время: 15 января 1997 года, 11:45, надо написать

TTime anytime;

anytime.SetTime(1, 15, 1997, 11, 45);

Предположим, надо установить только дату, при этом время класса по умолчанию равно текущему.

На данный момент инициализировать подобным образом TTime не так-то просто.

Перегрузка SetTime() с различным числом параметров дает возможность в программе передавать произвольное число аргументов, как в следующем выражении

anyTime.SetTime(1, 15, 1997)

В листинге 2.12 проводится новый класс TTime и несколько перегруженных функций-членов SetTime(). В заголовке TIME4.H содержатся только объявления и, следовательно, их нельзя скомпилировать. Следующие два листинга включают TIME4.H c его объявлением класса.

Листинг 2.12 TIME4.H ( с перегруженными функциями- членами)

1://time4.h-Объявление класса TTime

2:

3: #ifndef _ _TIME4_H

4: #define _ _TIME4_H 1

// Предотвращение нескольких #include

5:

6: #include <iostream.h>

7: #include <time.h>

8: #include <string.h>

9:

10: class TTime {

11: private:

12: long dt; // Дата и время – в //секундах от 1 января 1970 года

13: public:

14: void Display(void) { cout << ctime(&dt); }

15: void GetTime(int &m, int &d, int &y, int &hr, int &min);

// В строках 16-21 объявляется шесть //перегруженных функций-членов SetTime()

16: void SetTime(int m, int d, int y, int hr, int min);

17: void SetTime(int m, int d, int y, int hr);

18: void SetTime(int m, int d, int y);

19: void SetTime(int m, int d);

20: void SetTime(int m);

21: void SetTime (void);

22: char * GetTime(void);

23: {

24: char *cp = strdup(ctime (td));

25: return cp;

26: }

27: void ChangeTime(long nminutes) { dt += (nminutes * 60); }

28: };

29:

30: #endif // _ TIME4_H

В строках 16-21 объявляется шесть перегруженных функций-членов SetTime(). Все они имеют одинаковое имя и отличаются хотя бы одним параметром – таково минимальное требование, чтобы компилятор мог их различить. И хотя все функции-члены имеют одинаковое имя, их тела должны быть реализованы раздельно, как это показано в листинге 2.13.

Листинг 2.13. TIME4.CPP (реализация перегруженных функций-членов)

1://time4.cpp- реал-ция класса TTime

2:

3: #include <dos.h>

4: #include “time4.h”

5:

6: // Возвращает текущие данные-//члены дату и время

7: void TTime::GetTime(int &m, int &d, int &y, int &hr, int &min);

8: {

9: struct date ds;

10: struct time ts;

11:

12: unixtodos(dt, &ds, &ts );

13: y = ds.da_year;

14: m = ds.da_mon;

15: d = ds.da_day;

16: hr = ts.ti_hour;

17: min = ts.ti_min;

18: }

19:

20: // Устанавливает член dt

21: void Ttime : : SetTime(int m, int d, int y, int hr, int min)

22: {

23: struct date ds;

24: struct time ts;

25:

26: getdate(&ds); // Получение текущих даты и времени

27: gettime(&ts);

28: if (y >= 0) ds.da_year = y;

29: if (m >= 0) ds.da_mon = m;

30: if (d >= 0) ds.da_day = d;

31: if (hr >= 0) ts.ti_hour = hr;

32: if (min >= 0) ts.ti_min = min;

33: ts.ti_sec = 0;

34: ts.ti_hund = 0;

35: dt = dostounix(&ds, &ts);

36: }

37:

38: void TTime : : SetTime(int m, int d, int y, int hr)

39: {

40: SetTime(m, d, y, hr, -1);

41: }

42:

43: void TTime : : SetTime(int m, int d, int y)

44: {

45: SetTime(m, d, y, -1, -1);

46: }

47:

48: void TTime::SetTime(int m, int d)

49: {

50: SetTime(m, d, -1, -1, -1);

51: }

52:

53: void TTime : : SetTime(int m)

54: {

55: SetTime(m, -1, -1, -1, -1);

56: }

57:

58: void TTime : : SetTime(void)

59: {

60: SetTime(-1, -1, -1, -1, -1);

61: }

Если today  объект класса TType, оператор

today.SetTime(1, 15, 1998, -1, -1);

устанавливает дату, хранящуюся в today, равной 15 января 1998 года, но с текущим временем, поскольку эти два аргумента установлены равными -1.

Т.к. функция перегружена, можно написать

today.SetTime(1, 15, 1998);

Например, оператор

today.SetTime();

вызывается перегруженную функцию-член SetTime(), реализованную в строках 58-61 и не имеющую аргументов, которая, в свою очередь, вызывает версию с пятью аргументами для установки в today системной даты и времени.

В листинге 2.14 демонстрируется использование перегруженных функций-членов TTime.

Листинг 2.14 OVERMF.CPP (использование перегруженных функций-членов)

1: #include <iostream.h>

2: #include <stdio.h>

3: #include “time4.h”

4:

5: main()

6: {

7: TTime ap;

8:

9: ap.SetTime();

10: ap.Display();

11: ap.SetTime(8);

12: ap.Display();

13: ap.SetTime(8, 1);

14: ap.Display();

15: ap.SetTime(8, 1, 1996);

16: ap.Display();

17: ap.SetTime(8,1,1996,8);

18: ap.Display();

19:ap.SetTime(8,1,1996,8,30);

20: ap.Display();

21: return 0:

22: }

Д/з ??? какое время на дисплее

Параметры функций-членов по умолчанию

Многочисленные перегруженные функции-члены, подобные приведенным в строках 16-21 листинга 2.12, полезны, но зачастую приводят к путанице в коде.

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

Параметры функций-членов по умолчанию используются в объявлении классов.

В листинге 2.15, приводится новая версия функции SetTime() класса TTime, использующая параметры по умолчанию.

Листинг 2.15 TIME5.H (новая версия класса TTime c использованием параметров функций-членов по умолчанию)

1://time5.h-объявление класса TTime

2:

3: #ifndef __TIME5_H

4: #defaine__TIME5_H 1

// Предотвращение нескольких #include

5:

6: #include <iostream.h>

7: #include <stdio.h>

8: #include <string.h>

9:

10: class TTime {

11: private:

12: long dt; // Дата и время –в //секундах от 1 января 1970 года

13: public:

14: void Display(void) { cout << ctime(&dt); }

15: void GetTime(int &m, int &d, int &y, int &hr, int &min);

// Каждому из параметров //SetTime() присваивается значение //по умолчанию -1, //использовавшееся для //идентификации неуказанных //параметров в вызове этой //функции-члена.

void SetTime(int m = -1, int d = -1, int y = -1,

int hr = -1, int min = -1);

18: char *GetSTime(void)

19: {

20: char *cp = strdup(ctime(&dt));

21: return cp;

22: }

23: void ChangeTime(long nminutes) {dt += (minutes *60); }

24: }

25:

26: #endif // __TIME5_H

Каждому из параметров SetTime() в строках 16-17 присваивается значение по умолчанию -1, использовавшееся для идентификации неуказанных параметров в вызове этой функции-члена.

Значения параметров по умолчанию должны следовать за всеми прочими параметрами в объявлении функции-члена.

В данном объекте класса TTime с именем today оператор

today.SetTime(1,15, 1998);

передает дату 15 января 1998 года первым трем параметрам SetTime(). Поскольку неуказанные аргументы принимают значения по умолчанию, последние два аргумента неявным образом устанавливаются равными -1,

// компилируется так, как если бы //был написан

today.SetTime(1, 15, 1998, -1, -1);

Новая реализация класса TTime значительно проще в сравнении с перегрузкой функций-членов SetTime().

В листинге 2.16 приводится результат.

Значения функций-членов по умолчанию не приводятся в заголовке функции (при реализации). Значения по умолчанию могут присутствовать только в объявлении функции-члена.

Листинг 2.16 TIME5.CPP ( реализация упрощенного класса TTime)

1://time.cpp–реализация класса TTime

2:

3: #include <dos.h>

4: #include “time5.h”

5:

6: // Возвращает текущие //данные-члены даты и время

7: void::GetTime(int &m, int &d, int &y, int &hr, int &min)

8: {

9: struct date ds;

10: struct time ts;

11:

12: unixtodos(dt, &ds, &ts);

13: y = ds.da_year;

14: m = ds.da_mon;

15: d = ds.da_day;

16: hr = ts.ti_hour;

17: min = ts.ti_min;

18: }

19:

20: // Устанавливает член dt

21: void TTime : : SetTime(int m, int d, int y, int hr, int min)

22: {

23: struct date ds;

24: struct time ts;

25: //Получение текущих даты и

// времени

26: getdate(&ds);

27: gettime(&ts);

28: if (y >= 0) ds.da_year = y;

29: if (m >= 0) ds.da_mon = m;

30: if (d >= 0) ds.da_day = d;

31: if (hr >= 0) ts.ti_hour = hr;

32: if (min >= 0) ts.ti_min = min;

33: ts.ti_sec = 0;

34: ts.ti_hund = 0;

35: dt = dostounix(&ds, &ts);

36: }

В листинге 2.17 используется новый класс TTime. демонстрируется, что в этом случае

параметры функций-членов по умолчанию позволяют использовать переменное число аргументов в вызовах функции SetTime().

Конечно результат такой же, как и в приведенном ранее примере перегрузки, но реализация класса стала намного проще.

Листинг 2.17 DEFAULT.CPP (использование параметров функций-членов по умолчанию)

1: #include <iostream.h>

2: #include <stdio.h>

3: #include “time5.h”

4:

5: main()

6: {

7: TTime ap;

8:

9: ap.SetTime();

10: ap.Display();

11: ap.SetTime(8);

12: ap.Display();

13: ap.SetTime(8, 1);

14: ap.Display();

15: ap.SetTime(8, 1,1996);

16: ap.Display();

17: ap.SetTime(8,1,1996,8);

18: ap.Display();

19: ap.SetTime(8,1,1996,8,30);

20: ap.Display();

21: return 0:

22: }

%%%%%%%%%%%%%%%%%

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

До сих пор инициализация объекта класса происходила при его создании.

Возьмем любой из предыдущих классов TTime. Объявление

TTime anytime;

создает объект класса anytime типа TTime, но не инициализирует его данные-члены.

Если забыли инициализировать объект класса, оператор

аnytime.display();

скорее всего выведет всякий мусор или, по крайней мере, неверную дату и время.

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

В классах также может быть объявлен (но только один) деструктор, вызываемый для очистки при выходе объекта класса из области видимости.

Конструкторы и деструкторы похоже на обычные функции-члены, но они реже вызываются непосредственно в операторах программы.

С++ автоматически вызывает конструкторы и деструкторы для инициализации и очистки объектов класса.

В листинге 2.18 объявляться еще одна версия класса TTime. Новый класс имеет два конструктора для инициализации заново созданных объектов класса TTime. В нем также имеется деструктор для очистки старых объектов класса TTime, выходящих из области видимости.

Листинг 2.18. TIME6.H (объявление класса TTime с конструкторами и деструктором)

1://time6.h- объявление класса TTime

2:

3: #ifndef __TIME6_H

4: #defaine__TIME6_H 1

//Предотвращение нескольких #include

5:

6: #include <iostream.h>

7: #include <stdio.h>

8: #include <string.h>

9:

10: class TTime {

11: private:

12: long dt; // Дата и время – //в секундах от 1 января 1970 года

13: char *dts; // Представление //даты и времени в виде строки

//адрес строкового представления даты и времени

14: void DeleteDts(void);

// Удаляет указатель dts

15: public:

// конструктор

//выз-ся по умолчанию, т.к. без пар-ров

16: TTime();

// перегруженный конструктор

17: TTime(int m, int d = -1, int y = -1,

18: int hr = -1, int min = -1);

19: TTime(); // Деструктор

20: void Display(void) { cout << ctime(&dt); }

21: void GetTime(int &m, int &d, int &y, int &hr, int &min);

22: void SetTime(int m = -1, int d = -1, int y = -1,

23: int hr = -1, int min = -1);

24: const char *GetSTime(void);

25: void changeTime(long nminutes)

26: { dt += (nminutes *60); DeleteDts(); }

27: };

28:

29: #endif //__TIME6_H

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

Они всегда имеют такое же имя, как в классе, для которого объявляются. Они не всегда могут быть скомпилированы встраиваемыми.

В строке 16 объявляется TTime() в качестве конструктора класса TTime. Поскольку конструктор объявляется без параметров, он вызывается по умолчанию. В строках 17-18 объявляется второй перегруженный конструктор для TTime. Этот конструктор имеет одинаковое с классом имя, но на этот раз он объявлен с пятью целочисленным параметрами, из которых последние четыре передают значения по умолчанию -1. В TTime также объявлен в строке 19 деструктор.

В дополнение к конструкторам и деструктору новый класс TTime имеет еще два отличия. В строке 13 добавлен второй закрытый член класса – символьный указатель dts. Этот указатель содержит адрес строкового представления даты и времени. Хранение даты и времени в виде символьной строки помогает облегчить управление памятью в классе, а так же может улучить быстродействие программы. В строке 14 добавлена закрытая функция-член DeleteDts(), освобождающая память, на которую указывает dts. Закрытые функции-члены могут вызываться только другими функциями-членами класса и, как и другие закрытые члены, недоступны вне класса. Невозможно в произвольном операторе программы вызвать DeleteDts() и освободить память, на которую ссылается dts. Только члены класса имеют подобную привилегию.

реализация TTime в листинге 2.19. Как и в предыдущей версии класса TTime, TIME6.CPP –отдельный модуль, в котором отсутствует функция main(). Далее будет приведен листинг, использующий модуль объявления класса и его реализации.

Листинг 2.19. TIME6.CPP (реализация TTime)

1: // time6.cpp -- реализация класса TTime

2:

3: #include <dos.h>

4: #include “time6.h”

5:

6: // Конструктор по умолчанию

7: TTime::TTime()

8: {

9: dts = NULL; // Обнуление //текущей строки

//вызов с аргументами по умолчанию -1

10: SetTime(-1, -1, -1, -1, -1);

11: }

12:

13: // Перегруженный конструктор

14: TTime::TTime(int m, int d, int y, int hr, int min)

15: {

16: dts = NULL; // Обнуление //текущей строки

17: SetTime(m, d, y, hr, min);

18: }

19:

20: // Деструктор

21: TTime::TTime()

22: {

23: delete dts; // Удаление //строки, хранящейся в объекте

24: }

25:

26: // Удаление указатель dts

27: void TTime::DeleteDts(void)

28: {

29: delete dts; // Удаление строки, //хранящейся в объекте

30: dts = NULL; // Обнуление указатель

31: }

32:

33: // Возвращает текущие данные-//члены дату и время

34: void TTime::GetTime(int &m, int &d, int &y, int &hr, int &min);

35: {

36: struct date ds;

37: struct time ts;

38:

39: unixtodos(dt, &ds, &ts);

40: y = ds.da_year;

41: m = ds.da_mon;

42: d = ds.da_day;

43: hr = ts.ti_hour;

44: min = ts.ti_min;

45: }

46:

47: // Устанавливает член dt

48: void TTime : : SetTime(int m, int d, int y, int hr, int min)

49: {

50: struct date ds;

51: struct time ts;

52:

53: getdate(&ds); // Получение //текущих даты и времени

54: gettime(&ts);

55: if (y >= 0) ds.da_year = y;

56: if (m >= 0) ds.da_mon = m;

57: if (d >= 0) ds.da_day = d;

58: if (hr >= 0) ts.ti_hour = hr;

59: if (min >= 0) ts.ti_min = min;

60: ts.ti_sec = 0;

61: ts.ti_hund = 0;

62: dt = dostounix(&ds, &ts);

63: DeleteDts(); // Удаление //текущей строки

64: }

65:

66:const char *TTime::GetSTime(void)

67: {

68: if (dts) // Возвращает //текущую строку, если она //инициализирована

69: return dts;

// ctime() для преобразования даты и времени в строку ASCII

70: dts = strdup(ctime(&dts));

71: return dts;

72: }

В строках 7-11 приводится конструктор TTime по умолчанию – TTime(). Как и в случае всех прочих функций-членов, заголовку реализации предшествует имя класса и оператор разрешения области видимость. Хотя внешний вид заголовка TTime::TTime(), кажется, страдает от зеркального отражения, тем не менее он верно идентифицирует конструктор TTime(), как принадлежащий классу TTime (рис. 2.4).

Программирование внутренних операторов конструктора ничем не отличается от программирования других функций-членов или обычных функций. Конечно. Обязанности типичного конструктора ограничены присваиванием начальных значений данным-членам класса, выделением памяти, используемой объектом класса, и т.д. В данном случае в строке 16 символьный указатель dts устанавливается равным NULL, это значит, что указатель еще не ссылается на строку. Поскольку С++ автоматически вызывает конструктор для инициализации объекта класса TTime, следовательно, все такие объекты гарантированно имеют инициализированный указатель dts. Конструктор также вызывает функцию-член SetTime() с аргументами по умолчанию -1 (строка 10), устанавливая таким образом в объекте класса текущие дату и время.

Frame3

Рис. 2.4. детали и части конструктора

Второй перегруженный конструктор приводится в строках 14-18. похоже на конструкторе по умолчанию, но объявлен с параметрами даты и времени и может использоваться для инициализации значений объекта класса. Перегруженные конструкторы похожи на перегруженные функции-члены.

В любом классе можно объявить столько конструкторов, сколько потребуется, при условии, что они отличаются хотя бы одним своим параметром.

Конструкторы должны иметь одинаковое имя с классом, в котором они определены и, следовательно, перегружаются по определению.

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

Не все классы нуждаются в конструкторах, но в большинстве из них определен хотя бы один. В иных классах может быть дюжина конструкторов и даже более. Цель конструкторов обеспечить ясно определенную инициализацию объектов класса.

В листинге 2.20 демонстрируется инициализация объектов класса TTime конструкторам TTime().

Листинг 2.20. CONSTRUC.PP (использование конструкторов TTime)

1: #include <iostream.h>

2: #include <stdio.h>

3: #include “time6.h”

4:

5: main()

6: {

// В строках 7-12 объявляются //шесть объектов класса TTime и //инициализируются

7: TTime t1;

8: TTime t 2(8);

9: TTime t3(8, 1);

10: TTime t4(8, 1, 1996);

11: TTime t5(8, 1, 1996, 8);

12: TTime t6(8, 1, 1996, 8, 30);

13:

14: t1.Display();

15: t2.Display();

16: t3.Display();

17: t4.Display();

18: t5.Display();

19: t6.Display();

20: return 0;

21: }

В строках 7-12 объявляются шесть объектов класса TTime. С++ автоматически вызывает конструктора класса при его создании. Например, когда программа выделяет пространство для t1, как это объявлено в строке 7, вызывается конструктор по умолчанию для инициализации объекта.

В строках 8 -12 объявляются и инициализируются объекты класса, начиная с t2 и заканчивая t6, с указанием явных параметров в круглых скобках. Эти объявления имеют сходства с более ранними примерами, в которых объявлялся объект класса TTime и затем вызывались функции- члены SetTime() для присваивания значении данным-членам объекта. Конечно, с использованием конструкторов вся эта работа автоматически выполняется во время создания объектов.

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

Попробуйте с помощью встроенного отладчика исследовать, как в приведенном образце программы вызываются различные конструкторы TTime. С начала с помощью меню Project откройте CONSTRUC.IDE, затем выберите CONSTRUC. CPP в окне проекта для того, чтобы открыть этот файл. Поместите курсор на первый оператор mine() и нажмите <F5> для установки точки прерывания на этой строке. Установите также точке прерывания на следующих пяти строках. Все шесть строк должны выделяться на цветном мониторе красным цветом. Нажмите <Ctrl+F9> для компиляции и запуска программы. Выполнение прервется на первой точке прерывания. Для того чтобы определить, какой конструктор вызывается в операторе, нажмите <F9> для входа в тело конструктора. Это приведет вас к конструктору по умолчанию. Нажмите <Ctrl+F9> для продолжения выполнения программы до следующей точки останова и затем опять нажмите <F7> для входа в вызов функции, на этот раз вы попадете во второй конструктор класса. Повторяйте эти действия до тех пор, пока программа не начнет отображение.

Использование деструкторов

Еще один пример программы демонстрирует использование класса TTime из TTIM6.H и TIME6.CPP (листинги 2.18 и 2.19), а также показывает, как используется деструктор для очистки объекта класса при его выходе из области видимости.

Листинг 2.21 DESTRUC.CPP (использование деструктора TTime )

1: #include <iostream.h>

2: #include <stdio.h>

3: #include “time6.h”

4:

5: void f(void);

6:

7: main()

8: {

9: f();

10: return 0;

11: }

12:

13: void f(void)

14: {

// локальный объект today класса TTime

15: TTime today;

// т.к. локальный автоматический объект создается вместе с вызовом функции, в которой он объявлен, С++ вызывает для today конструктор TTime() по умолчанию

// локальный символьный указатель sp

16: const char *sp;

17:

// вызовы GetSTime() будут использовать созданную ранее строку

// Это сокращает количество выделений пространства в динамически распределяемой //области памяти для строкового предоставления даты и времени

18: sp = today.GetSTime();

19: cout << “First time: ” << sp;

20: sp = today.GetSTime();

21: cout << “Second time: ” << sp;

22: }

Функция main() в DESTRUC.CPP вызывает другую функцию f(), приведенную в строках 13-22. Внутри функции в строке 15 объявляется автоматический объект класса TTime today, локальный в области видимости функции. Поскольку локальный автоматический объект создается вместе с вызовом функции, в которой он объявлен, С++ вызывает для today конструктор TTime() по умолчанию в качестве части кода, выполняемого функцией при запуске. Подобная операция выполняется всякий раз при вызове функции. (вы можете проверить этот факт из интегрированной среды с помощью встроенного отладчика.)

В строках 18-21 вызывается функция-член GetSTime() для объекта класса today. Результат этой функции сохраняется в локальном символьном указателе sp. Вернемся к листингу 2.19, в котором приводится реализация GetSTime() (строки 66-72). Функция-член сначала проверяет, не содержит ли член dts нуль. Если нет, то возвращается dts, иначе вызываются strdup() и ctime() для преобразования текущей даты и времени в символьную строку, с сохранением адреса строки в символьном указателе dts _ закрытом члене класса. Таким образом, последующие вызовы GetSTime() будут использовать созданную ранее строку. Это сокращает количество выделений пространства в динамически распределяемой области памяти для строкового предоставления даты и времени, уменьшает фрагментацию динамически распределяемой области и улучшает быстродействия программы.

Поскольку класса TTime владеет указателем dts, ссылающимся на выделенный блок памяти, класс должен аккуратно управлять распределением этой памяти. Объект типа TTime не должен выходить из области видимости без освобождения выделенной этому объекту памяти, иначе это приведет к ошибкам, связанным с нехваткой памяти. Кроме того, если дата и время объекта класса TTime изменились (на пример, с помощью обращения к ChangeTime() и SetTime()), то не нулевой указатель dts должен быть удален и установлен равным 0, таким образом он будет выделен заново в следующем вызове GetSTime().

Вернемся к TIME6.H (листинг 2.18) и рассмотрим строку 19, в которой объявляется деструктор для класса TTime. Деструкторы обычно объявляется в открытой секции класса, но могут и не объявляться вовсе. Класс может иметь не более одного деструктор с именем класса, в котором он объявлен (как и все конструкторы). Только объявлению деструктора предшествует тильда (), которая используется в математике для обозначения разности. Деструкторы – антиподы конструкторов: то, что создано конструктором, может быть уничтожено деструктором.

Реализация деструктора ничем не отличается от других функций-членов. Вы можете усовершенствовать код, объявив деструктора встраиваемым. В листинге 2.19 в строках 21-24 приводится реализация деструктора класса TTime:

TTime::TTime()

{

delete dts ; // Удаление строки, ранящейся в объекте

}

Так же, как конструкторы и функции-члены, имя деструктора TTime() предваряется именем класса и оператором разрешения области видимости TTime::, что идентифицирует деструктор как член класса TTime.единственный оператор в деструкторе TTime удаляет dts, (можно не проверять dts на содержание ненулевого значения; оператор delete проигнорирует нулевые аргументы-указатели.)

Если объект класса выходит из области видимости, С++ автоматически вызывает конструктор объект класса, если таковой имеется. Это дает объекту удобную возможность для самоочистки, например удаления памяти, выделенной конструктором или функцией-членом.

Помните: конструкторы создает, деструкторы разрушают. Класс может иметь много конструкторов, следовательно, программа может создавать объекты различными способами. Конечно, класс может иметь не более одного деструктора, который вызывается автоматически при уничтожении объекта или при выходе его из области видимости. Если необходимо по-разному уничтожать объекты, деструктор может вызывать функции-члены, использовать оператор switch и другие средства для адекватных действий в различных ситуациях.

“Жизнь” объекта

объекты класса могут быть глобальными или локальными в функции.

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

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

Природа объекта, а именно: является ли он глобальными, локальным, адресуемым указателем и т.д.  влияет на то, когда будут вызываться конструкторы и деструктор этого объекта класса.

При создании объекта С++ автоматически вызывает конструктор этого объекта по умолчанию или другой конструктор, который вы укажете в объявлении объекта.

Когда объект выходит из области видимости, С++ вызывает его конструктор.

На рис. 2.5 на временном отрезке представлены все эти действия с отметкой типичных событий, происходящих в жизни объекта.

Следующие замечания помогут прояснить, когда вызывается конструкторы и деструкторы для объектов классов различных типов.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]