Новая версия сайта находится на стадии beta-тестирования

Урок #12

Понятие структуры

На прошлых уроках мы рассматривали только функциональное программирование. Сейчас же мы перейдем на новый этап - структурное программирование. С некоторой структурой данных мы уже связывались, это были массивы, но это не совсем то, что нам нужно. Массивы могут совмещать в себе несколько значений одного типа. Но что, если мы хотим создать некоторое объединение нескольких типов в один объект? Например, данные про котиков: необходимо знать его имя (string), вес (double) и породу (объект перечисления Breed). Данные поля имеют типы, которые почти несовместимы друг с другом. Конечно, можно сделать все типом string. Но чтобы записать изменения в весе кота, необходимо будет переконвертировать поле веса в числовой тип, произвести необходимые операции и затем переконвертировать в string обратно. Сейчас решим эту проблему! Взглянем на код снизу:

struct Cat {
	string name;
	double weight;
	Breed breed;
};

Так же перед описанием структуры опишем и само перечисление Breed (если породы Вашего любимого котика здесь нет, можете ее гордо написать на самое первое место :) Я бы с радостью перечислил все породы, но их очень много)

enum Breed {Abyssinian, Balinese, Bengal, BritishShorthair, Himalayan};

Таким образом мы получили структуру данных, которая совмещает в себе все эти поля. Обратите внимание, что обязательно после ее описания ставить точку с запятой и позже будет сказано почему. Cat - название структуры, а name, weight и breed - ее поля.

Научимся работать с этой структурой. Объявляется объект данной структуры, как и переменная обычного стандартного типа: Cat myCat. Чтобы получить доступ к нужному нам полю, необходимо использовать оператор точка. Например, myCat.name = "Smokey" - команда, которая присваивает полю name объекта myCat строку "Smokey". Заполним поля и для остальных полей нашего объекта. Для этого напишем 3 функции, которые будут принимать ссылку на изменяемый объект, а также одно из изменяемых значений:

 void setName(Cat & cat, string name) {
	cat.name = name;
}

void setWeight(Cat & cat, double weight) {
	cat.weight = weight;
}

void setBreed(Cat & cat, Breed breed) {
	cat.breed = breed;
}

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

void printCat(Cat & cat) {
	cout << cat.name << " (" << cat.breed << ")" << " is " << cat.weight << endl;
}

Обратите внимание на то, что мы писали отдельные функции для изменения каждого поля нашей структуры. Но это можно писать даже в функции main, не используя никакие функции:

int main() {
	Cat myCat;
	myCat.name = "Smokey";
	myCat.weight = 7.1;
	myCat.breed = Bengal;
}

Но не надо так делать! Это может показаться легче, но что, если мы захотим покормить котика. Вследствии этого его масса увеличится на 10% от массы съеденной пищи. Получится, что для изменения поля нам необходимо выполнить сразу 2 действия: ввести массу еды и добавить 10% от нее к массе котика. Скорее всего Вы не знали, что только 10% еды идет на рост организма, который ей питается. Следовательно, не будет об этом знать и пользователь, которому Вы любезно предложите воспользоваться Вашим новым кодом для работы с котиками. Напишем функцию gainWeight:

void gainWeight(Cat & cat, double foodWeight) {
	double gainedWeight = foodWeight * 0.1;
	cat.weight += gainedWeight;
}

Указатели на объект структуры

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

Cat * myCat;
myCat = new Cat;

Ничего необычного, да? Но теперь вопрос в следующем: как же получать доступ к полям объекта? Если попробовать написать *myCat.name = "Smokey", то мы получим ошибку. Оператор "точка" имеет приоритет исполнения выше, чем оператор разыменования, так что программа сперва пытается найти поле name у ссылки, а не у объекта. Для этого изменим порядок исполнения вручную: (*myCat).name = "Smokey". Это работает, но выглядит немного запутанно. Заменой этой конструкции есть оператор ->, который состоит из двух символов: "минус" и "больше". Теперь же присвоение строки имени в соответствующее поле выглядит гораздо проще и понятнее myCat->name = "Smokey".

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

Возможные вопросы по теме:

Вопросов еще нет

Добавляйте свои вопросы в комментарии. Лучшие попадут в статью :)

Урок #11 Урок #13