Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
тех прог.doc
Скачиваний:
13
Добавлен:
14.11.2019
Размер:
3.59 Mб
Скачать

15.7.Копирование объектов класса

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

Программа 46. Копирование объектов

// Файл DateCl_5.cpp

// Здесь нужно поместить программу 43 за исключением функции main

int main()

{

Date Today; // Today инициализируется конструктором по умолчанию

Date Tomorrow = Today; // Tomorrow инициализируется датой Today

Tomorrow.Add_Day(); // Увеличение даты на 1 день

cout << "\nСегодня: "; Today.Print();

cout << "\nЗавтра: "; Tomorrow.Print();

Today = Tomorrow; // Присваивание дат

cout << "\nToday: "; Today.Print();

getch();

return 0;

}

Программа напечатает:

Сегодня: 5.4.2006

Завтра: 6.4.2006

Today: 6.4.2006

Инициализация производится инструкциями вида:

Date Tomorrow = Today;

Инициализация выполняется на этапе компиляции и состоит в том, что под объект выделяется память, и в эту память заносятся задаваемые начальные значения. В результате инициализации Tomorrow становится копией Today, так как инициализация производится почленным копированием.

Присваивание вида:

Today = Tomorrow;

производится на этапе выполнения программы. При присваивании также производится почленное копирование, поэтому Today становится копией Tomorrow.

15.8.Управление доступом

Члены класса могут быть закрытыми (private), открытыми (public) и защищенными (protected). Защищенные члены являются закрытыми, но доступными в классах, производных от данного класса. (Создание производных классов называется наследованием, см.§20.3).

Структуры и классы

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

struct S{

};

эквивалентно

class S{

public:

};

После ключевого слова public перечисляются открытые члены.

С помощью ключевого слова private можно закрыть часть членов структуры:

struct S{

private:

// Закрытые члены структуры

public:

// Открытые члены структуры

};

Разделов public и private может быть несколько, они могут располагаться в любой последовательности.

Правила доступа

Действуют следующие правила доступа к членам класса:

  • К закрытым (private) членам класса имеют доступ только методы класса и функции-друзья класса.

  • К защищенным (protected) членам имеют доступ методы и друзья данного класса и методы и друзья классов, производных от него.

  • К открытым (public) членам имеет доступ любая функция.

15.9.Ссылка на себя

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

Программа 47. Модификация дат

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

// Файл DateCl_6.cpp

class Date{

int d, m, y; // День, месяц и год

public:

Date(int = 0, int = 0, int = 0); // Конструктор

Date& Add_Year(int n); // Добавить к дате n лет

Date& Add_OneDay(); // Добавить к дате 1 день

Date& Add_Day(int n); // Добавить к дате n дней

Date& Add_OneMonth(); // Добавить к дате 1 месяц

Date& Add_Month(int n); // Добавить к дате n месяцев

void Print();

};

#include <iostream.h>

void Date::Print()

{

cout << d << '.' << m <<'.'<< y;

}

// leap: возвращает 1, если год year високосный и 0, если нет

int leap(int year)

{ return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; }

Date& Date::Add_Year(int n)

{

if(m == 2 && d == 29 && leap(y + n) != 1){ m = 3; d = 1; }

y += n;

return *this; // Возвращаем ссылку на измененный объект

}

Здесь внутри функции Add_Year ключевое слово this имеет значение указателя на тот объект класса Date, для которого функция вызвана. Например, далее в main есть инструкция вызова функции Add_Year для объекта Studies:

Studies.Add_Year(4);

Здесь во время работы Add_Year указатель this имеет значение адреса переменной Studies, а выражение *this есть сам объект Studies.

// Массив дней в месяцах для невисокосного и високосного года

char daytab[2][13] ={{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},

{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

};

Date& Date::Add_OneDay()

{

if(d < daytab[leap(y)][m]) // Не последний день месяца

d++;

else if(m < 12){ // Последний день месяца, но не последний года

d = 1; m++;

}

else{ // Последний день года

d = 1; m = 1; y++;

}

return *this;

}

Увеличение даты на n дней реализуется n-кратным вызовом функции увеличения даты на 1 день.

Date& Date::Add_Day(int n) // Добавить к дате n дней

{

for(int i = 0; i < n; i++) // Вызываем n раз функцию

Add_OneDay(); // увеличения даты на 1 день

return *this;

}

Если исходная дата приходится на декабрь, через месяц будет то же число января следующего года. Для 28, 29, 30 или 31 января, считаем, что через 1 месяц будет последнее число февраля. Последнее число следующего месяца будет также, если исходная дата – последнее число месяца, независимо от числа дней в месяцах.

Date& Date::Add_OneMonth() // Добавить к дате 1 месяц

{

if(m == 12){ // Если декабрь,то

m = 1; y++; // будет январь следующего года

}

else if((m == 1 && d > 28) || d == 31){ // Если январь, число > 28 или

// последний день промежуточного месяца,

m++; // наступит последнее число

d = daytab[leap(y)][m]; // следующего месяца

}

else

m++; // Следующий месяца

return *this;

}

Date& Date::Add_Month(int n) // Добавить к дате n месяцев

{

for(int i = 0; i < n; i++) // n раз

Add_OneMonth(); // добавляем по 1 месяцу

return *this;

}

// Реализация конструктора

#include <dos.h>

Date::Date(int dd, int mm, int yy)

{

date sysd; // Системная дата

getdate(&sysd); // Получение системной даты

d = dd ? dd : sysd.da_day;

m = mm ? mm : sysd.da_mon;

y = yy ? yy : sysd.da_year;

}

#include <conio.h>

int main()

{

Date Studies(1, 9, 2005);

cout << "Начало учебы: "; Studies.Print(); cout << endl;

Studies.Add_Year(4);

Studies.Add_Month(9);

Studies.Add_Day(21);

cout << "Конец учебы: "; Studies.Print(); cout << endl;

Date Today; // Использование конструктора по умолчанию, сегодня

cout << "Сегодня: "; Today.Print(); cout << endl;

Today.Add_Year(1).Add_Month(1).Add_Day(1);

cout << "Через 1 год, 1 месяц и 1 день будет ";

Today.Print(); cout << endl;

getch();

return 0;

}

Программа выдает:

Начало учебы: 1.9.2005

Конец учебы: 22.6.2010

Сегодня : 12.4.2006

Через 1 год 1 месяц 1 и один день будет 13.5.2007

Обсудим инструкцию

Today.Add_Year(1).Add_Month(1).Add_Day(1);

Когда есть несколько операторов точка (.), они выполняются слева направо, то есть приведенная инструкция эквивалентна следующей:

((Today.Add_Year(1)).Add_Month(1)).Add_Day(1);

Выражение Today.Add_Year(1) во внутренних скобках равно дате Today, увеличенной на 1 год, так как Add_Year возвращает ссылку на объект, для которого вызывается. Далее для этой измененной Today вызывается Add_Month, которая также возвращает дату Today, увеличенную на 1 месяц, которая затем увеличивается на 1 день функцией Add_Day. Возможность писать подобные цепочки вызовов функций обеспечивается тем, что функции возвращают ссылки на объекты.