Определение и инициализация объектов данных
Теперь, чтобы завладеть вниманием пользователя, выполним короткий тест. Мы отобразим два числа из числовой последовательности и предложим пользователю угадать следующие значения в последовательности. Например,
The values 2,3 from two consecutive elements of a numerical sequence. What is the next value?
Эти значения - третий и четвертый элементы из последовательности Фибоначчи: 1, 1, 2, 3, 5, 8, 13 и т. д. Последовательность Фибоначчи начинается с двух элементов - единиц. Каждый следующий элемент это сумма двух предшествующих.
Если пользователь введет 5, мы поздравим его и спросим, хочет ли он попробовать другую числовую последовательность. Любое другое введенное значение - неверно, и мы спросим пользователя, хочет ли он погадать еще.
Чтобы поддержать интерес к программе, мы сохраним текущий счет, основанный на отношении правильных ответов к числу попыток.
Программа нуждается, по меньшей мере, в пяти объектах: объекте строкового класса для сохранения имени пользователя, трех целых объектах класса для запоминания по очереди попыток, числа попыток, числа успешных попыток, и объект класса чисел с плавающей точкой для запоминания счета.
Для определения объектов данных мы должны ввести имена и тип данных. Имена могут быть любыми комбинациями букв, цифр, подчеркиваний. Буквы регистрозависимые. Каждое из имен user_name, User_name, uSeR_nAmE и user_Name относится к разным объектам.
Имя не должно начинаться с цифры. Например, l_name неправильно, name_l - правильно. Также имя не должно совпадать с ключевыми словами языка. Например, delete - ключевое слово языка, так что мы не должны использовать его в нашей программе. (Это объясняет, почему оператор удаления символа из строкового класса - это erase (), а не deleted).
Каждый объект должен быть своего типа данных. Имя объекта позволяет нам обратиться к нему непосредственно. Тип данных определяет область значений, сохраняемых объектом, и количество памяти, необходимой для запоминания этого значения.
Мы видели определение user_name в предыдущем разделе. Перенесем то же определение в новую программу:
#include <string> string user_name;
Класс - программно-определенный тип данных. С++ также поддерживает множество встроенных типов данных: булевы, целые, с плавающей точкой и символьные. Ключевые слова, ассоциированные с каждым из них, позволяют нам определить тип данных. Например, для запоминания значения, введенного пользователем, мы определим объект целого типа:
Int usr_val;
Int - ключевое слово языка определяющее, что объект usr_val - целого типа. Оба объекта: число попыток, сделанных пользователем и число правильных ответов, - объекты целого типа. Разница только в том, что мы бы хотели дать им начальное значение «О». Мы можем вывести каждое на отдельную строку:
Int num_.trіes = 0; int num_right = 0;
Или определить их в одной строке через запятую:
Int num_tries = 0, num_right = 0;
В общем, лучше придерживаться правила инициализировать объект данных, даже если значение только обозначает, что объект не имеет полезного значения вовсе. Я не инициализировал usr_val, потому что значение будет получено непосредственно из пользовательского ввода прежде, чем программа как-то использует объект.
Альтернативный вариант инициализации - использовать так называемый конструкционный синтаксис
Int num_.tries (0);
Почему есть два инициализационных синтаксиса? Хуже того, почему я сейчас об этом говорю? Что ж, посмотрим, отвечает ли мое объяснение на оба вопроса.
Использование оператора присваивания для инициализации пришло из языка С. Оно хорошо работает с объектами данных встроенных типов и классами объектов, которые могут быть инициализированы единственным значением, например строковым классом:
String sequence_name = "Fibonacci";
Однако данный способ не так хорош для класса объектов, которые требуют нескольких значений для инициализации, как, например, класс стандартной библиотеки комплексных чисел, где каждое требует двух значений: первое - для действительной части, второе - для мнимой. Альтернативный конструкционный синтаксис был введен для поддержки многозначной инициализации:
#include <complex> complex<double> pureі(0, 7);
Странная нотация скобок, следующая за complex, означает, что класс комплексных чисел - класс шаблонов. Класс шаблонов позволяет нам определять класс без спецификации типа данных одного или всех членов класса.
Класс комплексных чисел, например, состоит из двух членов объекта данных. Один представляет реальную часть числа, второй - мнимую. Эти члены должны быть числами типа данных с плавающей точкой, но какого? С++ поддерживает три типа чисел с плавающей точкой: единичной точности, представляемых ключевым словом float; двойной точности, представленной ключевым словом double; и расширенной
Точности, представленной двумя ключевыми словами long double.
Механизм класса шаблонов позволяет программисту откладывать определение типа данных, используя класс шаблонов. Это дает ему возможность вставить «заглушку», которую позднее он заполнит реальным типом данных. В предыдущем примере использовался выбор данных типа класса комплексных чисел double.
Что ж, возможно, появляется больше вопросов, чем получается ответов. Это происходит от того, что шаблоны, под держиваемые С++, двух инициализационных синтаксисов для встроенных типов данных. Когда встроенные типы данных и программно определенный класс типов имеют разный иници- ализационный синтаксис, невозможно написать шаблон, который поддерживает и встроенный класс, и класс типа данных. Унификация синтаксиса упрощает разработку шаблонов. К сожалению, раскрытие синтаксиса приводит к появлению еще большей путаницы!
Счет пользователя должен быть значением с плавающей точкой, поскольку возникает нецелое отношение. Мы определим его типом double:
Double usr_score = 0.0;
Нам также нужно сохранить место для ответов пользователя yes/по: Make another try? Try another sequence?
Мы можем сохранить ответы пользователя в символьном объекте данных:
Char usr_more;
Cout « "Try another sequence? Y/N? "; cin » usr_more;
Ключевое слово char относится к символьному типу. Символ окаймляется апострофами, обозначая ' а', ' 7 ', '; ' и т. д. Некоторые специальные встроенные символьные обозначения приведены ниже (их иногда называют эскейп последовательности):
n' newline (новая строка) "t" tab (табуляция) "" null (нуль) ""' single quote (апостроф) double
Quote (кавычки) "\" backslash (обратная косая черта)
Например, для создания перевода на новую строку и табуляции перед вводом имени пользователя мы можем написать:
Cout « "n" « "t" « user_name;
Можно также объединить в строку отдельные символы:
Cout « "nt" « user_name;
Обычно мы используем эти специальные символы в буквенной строке. Например, для представления пути к файлу в системе Windows необходимо ставить обратные косые черточки:
"F:\essent ial\programs\chapter1\chl_main. срр"?
С++ поддерживает встроенный булев тип данных для представления значений true/false. В нашей программе, например, мы можем определить булев объект для контроля над необходимостью вывода на дисплей следующей числовой последовательности:
Bool go_for_it = true;
Булев объект обозначен ключевым словом bool. Он может сохранять два буквенных значения: true или false.
Все определенные объекты данных затем модифицируются в ходе нашей программы. go_for_it, например, в конечном счете, установится в false, a usr__score обновляется с каждой попыткой пользователя.
Иногда необходимо наличие объекта для представления постоянных значений: максимального числа попыток, определяемых для пользователя или значения числа «пи». Объекты, сохраняющие эти значения, не будут меняться по ходу программы. Как мы можем предотвратить случайное изменение данных объектов? Заручиться поддержкой языка, объявив эти объекты, как const:
Const int max_tries =3; const double pi = 3.14159;
Объекты const не могут изменяться после инициализации их значения. Любые попытки переустановить значение объекта const приведут к ошибке при компиляции. Например:
Max_tries = 42; // error: объект const