Опубликован: 25.08.2010 | Доступ: свободный | Студентов: 6114 / 607 | Оценка: 3.91 / 3.44 | Длительность: 11:09:00
Лекция 5:

Классы

< Лекция 4 || Лекция 5: 1234 || Лекция 6 >

Описание объектов

Конкретные переменные типа данных "класс" называются экземплярами класса, или объектами. Время жизни и видимость объектов зависит от вида и места описания и подчиняется общим правилам С++:

monster Vasia;			// Объект класса monster с параметрами по умолчанию
monster Super(200, 300);// Объект с явной инициализацией
monster stado[100];		// Массив объектов с параметрами по умолчанию
/* Динамический объект (второй параметр задается по умолчанию) */
monster *beavis = new monster (10);	 
monster &butthead = Vasia;	// Ссылка на объект

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

Доступ к открытым ( public ) элементам объекта аналогичен доступу к полям структуры. Для этого используются операция . (точка) при обращении к элементу через имя объекта и операция -> при обращении через указатель:

объект.поле
указатель -> поле
(*указатель).поле
объект.метод( параметры )
указатель -> метод( параметры )
(*указатель).метод( параметры )

Обращение к открытому полю и вызов метода для массива объектов:

имя_массива[ индекс ].поле
имя_массива[ индекс ].метод( параметры )

Например:

int n = Vasia.get_ammo();
stado[5].draw;
cout << beavis->get_health();

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

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

class monster{
...
int get_health() const {return health;}
};
const monster Dead (0,0); 	// Константный объект
cout << Dead.get_health();

Константный метод:

  • объявляется с ключевым словом const после списка параметров;
  • не может изменять значения полей класса;
  • может вызывать только константные методы;
  • может вызываться для любых (не только константных) объектов.

Рекомендуется описывать как константные те методы, которые предназначены для получения значений полей.

Указатель this

Каждый объект содержит свой экземпляр полей класса. Методы места в классе не занимают и не дублируются для каждого объекта. Единственный экземпляр метода используется всеми объектами совместно, поэтому нестатический метод должен "знать", для какого объекта он вызван.

Каждый нестатический метод, помимо явно объявленных параметров, получает еще один скрытый параметр: константный указатель на объект, для которого он вызван. В С++ это указатель обозначается зарезервированным словом this. Когда имя параметра метода совпадает с именем поля класса, доступ к полю выполняется через этот указатель (например, this -> num).

Выражение *this представляет собой разыменование указателя и имеет тип определяемого класса. Обычно это выражение возвращается в качестве результата, если метод возвращает ссылку на свой класс ( return *this; ).

Для иллюстрации использования указателя this добавим в приведенный выше класс monster новый метод, возвращающий ссылку на наиболее здорового (поле health ) из двух монстров, один из которых вызывает метод, а другой передается ему в качестве параметра (метод нужно поместить в секцию public описания класса):

monster & the_best(monster &M)
{
if( health > M.get_health()) 
  return *this;
return M;
}
... 
monster Vasia(50), Super(200);
// Новый объект Best инициализируется значениями полей Super
monster Best = Vasia.the_best(Super);

Конструкторы

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

  • Конструктор не возвращает значения, даже типа void. Нельзя получить указатель на конструктор.
  • Класс может иметь несколько конструкторов с разными параметрами для разных видов инициализации (при этом используется механизм перегрузки).
  • Конструктор, который можно вызвать без параметров, называется конструктором по умолчанию.
  • Параметры конструктора могут иметь любой тип, кроме этого же класса. Можно задавать значения параметров по умолчанию. Их может содержать только один из конструкторов.
  • Если программист не указал ни одного конструктора, компилятор создает его автоматически (кроме случая, когда класс содержит константы и ссылки, поскольку их необходимо инициализировать). Такой конструктор вызывает конструкторы по умолчанию для полей класса и конструкторы базовых классов.
  • Конструкторы не наследуются.
  • Конструктор не может быть константным, статическим и виртуальным (нельзя использовать модификаторы const, virtual и static ).
  • Конструкторы глобальных объектов вызываются до вызова функции main. Локальные объекты создаются, как только становится активной область их действия. Конструктор запускается и при создании временного объекта (например, при передаче объекта из функции).

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

Конструкторы часто вызываются неявно для создания временных объектов. Обычно это происходит в следующих случаях:

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

Примеры:

monster Super(200, 300), Vasia(50);
monster X = monster(1000);

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

При создании динамического массива вызывается конструктор без аргументов.

В качестве примера класса с несколькими конструкторами усовершенствуем описанный ранее класс monster, добавив в него поля, задающие цвет ( skin ) и имя ( name ):

enum color {red, green, blue};	//	Возможные значения цвета
class monster
{
int health, ammo;
color skin;
char *name;
public:
	monster(int he = 100, int am  = 10);
	monster(color sk);
	monster(char * nam);
...
};
//--------------------------------
monster::monster(int he, int am)
	{ health = he; ammo = am; skin = red; name = 0;}
//--------------------------------
monster::monster(color sk)
  {
  switch (sk)
	{
	case red: health = 100; ammo = 10; skin = red; name = 0; break;
	case green: health = 100;ammo = 20;skin = green;name = 0;break;
	case blue: health = 100; ammo = 40; skin = blue;name = 0;break;
	}
}
//--------------------------------
monster::monster(char * nam)
{
/* К длине строки добавляется 1 для хранения нуль-символа */
name = new char [strlen(nam) + 1];	
strcpy(name, nam);
health = 100; ammo = 10; skin = red;
}
//--------------------------------
monster * m = new monster ("Ork");
monster Green (green);

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

Существует еще один способ инициализации полей в конструкторе (кроме уже описанного присваивания полям значений параметров) - с помощью списка инициализаторов, расположенным после двоеточия между заголовком и телом конструктора:

monster::monster(int he, int am):
	health (he), ammo (am), skin (red), name (0){}

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

Конструктор копирования

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

T::T(const T&) { ... /* Тело конструктора */ }

где T - имя класса. Этот конструктор вызывается в тех случаях, когда новый объект создается путем копирования существующего:

  • при описании нового объекта с инициализацией другим объектом;
  • при передаче объекта в функцию по значению;
  • при возврате объекта из функции.

Если программист не указал ни одного конструктора копирования, компилятор создает его автоматически. Такой конструктор выполняет поэлементное копирование полей. Если класс содержит указатели или ссылки, это, скорее всего, будет неправильным, поскольку и копия, и оригинал будут указывать на одну и ту же область памяти.

Запишем конструктор копирования для класса monster. Поскольку в нем есть поле name, содержащее указатель на строку символов, конструктор копирования должен выделять память под новую строку и копировать в нее исходную:

monster::monster(const monster &M)
{
if (M.name)
  {
  name = new char [strlen(M.name) + 1];
  strcpy(name, M.name);
  }
  else name = 0;
health = M.health; ammo = M.ammo; skin = M.skin;
}
...
monster Vasia (blue);	
monster Super = Vasia;	// Работает конструктор копирования
monster *m = new monster ("Ork");
monster Green = *m; 		// Работает конструктор копирования
< Лекция 4 || Лекция 5: 1234 || Лекция 6 >
Dana Kanatkyzi
Dana Kanatkyzi
Здравствуйте.Помогите решить задачу минимум 4 чисел.Условие такое:"Напишите функцию int min (int a, int b, int c, int d) (C/C++)"находящую наименьшее из четырех данных чисел."Заранее спасибо!
Юрий Семевский
Юрий Семевский
Россия, Санкт-Петербург
Александр Богдашов
Александр Богдашов
Россия