Учимся программировать на языке C++

         

Более внимательный взгляд на C++


В уроке 1 вы создали несколько программ на C++. В то время ваша цель заключалась в том, чтобы понять процесс создания и компиляции программ на C++, а не в том, чтобы понять операторы C++. В данном уроке вы впервые более внимательно рассмотрите операторы, из которых состоит программа на C++. Вы увидите, что большинство программ на C++ придерживаются одного и того же формата: начинаются с одного или нескольких операторов #include, содержат строку void main(void), а затем набор операторов, сгруппированных между левой и правой фигурными скобками. Из этого урока вы поймете, что эти несколько запугивающие операторы реально очень просто освоить. К концу данного урока вы изучите следующие основные концепции:

Оператор #include обеспечивает преимущества использования заголовочных файлов, которые содержат операторы C++ или программные определения.

Основная часть программы на C++ начинается с оператора void main(void).

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

При выводе на экран ваши программы будут широко использовать выходной поток cout.

Когда вы создаете программы на C++, вы реально работаете в терминах операторов, но не инструкций. Позже вы изучите оператор присваивания, который присваивает значения переменным, оператор if, который позволяет программе принимать решения и т. д. А пока мы просто будем ссылаться на содержимое вашей программы, как на операторы программы.



C++ автоматически добавляет NULL к строковым константам


Все созданные вами программы использовали символьные строковые константы, заключенные внутри двойных кавычек, как показано ниже:

"Это строковая константа"

При создании символьной строковой константы компилятор C++ автоматически добавляет символ NULL, как показано на 17.2.

17.2. Компилятор C++ автоматически добавляет символ NULL к строковым константам.

Когда ваши программы выводят символьные строковые константы с помощью выходного потока cout, cout использует символ NULL (который компилятор добавляет к строке) для определения последнего символа вывода.

Использование символа NULL

Символьная строка представляет собой массив символов, за которыми следует символ NULL ('\0'). При объявлении символьной строки вы объявляете массив типа char. Когда программа позднее присваивает символы строке, она отвечает за добавление символа NULL, который представляет конец строки.

Если вы используете строковые константы, заключенные в двойные кавычки, компилятор C++ автоматически добавляет символ NULL. Большинство функций C++ используют символ NULL для определения последнего символа строки.

Следующая программа LOOPNULL.CPP слегка изменяет предыдущую программу, используя цикл for для вывода содержимого строки:

#include iostream.h

void main(void)

{

char alphabet[34]; //33 символа плюс NULL char letter;

int index;

for (letter = 'A', index = 0; letter = 'Я'; letter++,index++) alphabet[index] = letter;

alphabet[index] = NULL;

for (index = 0; alphabet[index] 1= NULL; index++) cout alphabet[index];

cout endl;

}

Как видите, цикл for по одному исследует символы строки. Если символ не NULL (не последний символ строки), цикл выводит символ, увеличивает индекс, и процесс продолжается.



C++ ПРЕДСТАВЛЯЕТ ИСКЛЮЧИТЕЛЬНЫЕ СИТУАЦИИ КАК КЛАССЫ


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

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

class file_open_error {};

class file_read_error {};

class file_write_error {};

Позже в этом уроке вы создадите исключительные ситуации, которые используют переменные и функции-элементы класса. А пока просто поверьте, что каждая исключительная ситуация соответствует классу.



Частные и общие данные


В уроке 21 вы создали свои первые классы в C++. При этом вы включали метку public в определение класса, чтобы обеспечить программе доступ к каждому элементу класса. Из данного урока вы узнаете, как атрибуты public и private управляют доступом к элементам класса со стороны программы. Вы узнаете, что ваши программы могут обратиться к общим (public) элементам из любой функции. С другой стороны, ваша программа может обращаться к частным (private) элементам только в функциях данного класса. Этот урок подробно исследует частные и общие элементы. К концу данного урока вы освоите следующие основные концепции:

Чтобы управлять тем, как ваши программы обращаются к элементам класса, C++ позволяет вам определять элементы как частные или общие.

Частные элементы дают возможность классу скрыть информацию, которую программе не требуется знать.

Класс, использующий частные элементы, обеспечивает интерфейсные функции, которые обращаются к частным элементам класса.

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



Частные элементы и друзья


Как вы уже знаете, ваши программы могут обращаться к частным (private) элементам класса только с помощью функций-элементов этого же класса. Используя частные элементы класса вместо общих во всех ситуациях, где это только возможно, вы уменьшаете возможность программы испортить значения элементов класса, так как программа может обращаться к таким элементам только через интерфейсные функции (которые управляют доступом к частным элементам). Однако в зависимости от использования объектов вашей программы, иногда вы можете существенно увеличить производительность позволяя одному классу напрямую обращаться к частным элементам другого. В этом случае уменьшаются издержки (требуемое время выполнения) на вызов интерфейсных функций. В подобных ситуациях C++ позволяет определить класс в качестве друга (friend} другого класса и разрешает классу-другу доступ к частным элементам этого другого класса. В этом уроке объясняется, как ваши программы могут указать, что два класса являются друзьями. К концу данного урока вы освоите следующие основные концепции:

Используя ключевое слово friend, класс может сообщить C++, кто является его другом, т. е. другими словами, что другие классы могут обращаться напрямую к его частным элементам.

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

C++ позволяет ограничить дружественный доступ определенным набором функций.

Частные (private) элементы позволяют вам защищать классы и уменьшить вероятность ошибок. Таким образом, вы должны ограничить использование классов-друзей настолько, насколько это возможно. Иногда программа напрямую может изменить значения элементов класса, это увеличивает вероятность появления ошибок.



ЧАСТНЫЕ ЭЛЕМЕНТЫ КЛАССА НЕ ВСЕГДА ЯВЛЯЮТСЯ ДАННЫМИ


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



ЧЕМ МАКРОКОМАНДЫ ОТЛИЧАЮТСЯ ОТ ФУНКЦИЙ


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

В случае с макрокомандой препроцессор заменяет в вашем коде каждую ссылку на макрокоманду соответствующим определением макрокоманды. Например, если предыдущая программа использует макрокоманду CUBE в 100 различных местах, препроцессор подставит код макрокоманды 100 раз. Используя макрокоманды, вы избегаете издержек на вызов функции (издержек на помещение параметров в стек и удаление их оттуда, а также издержек на выполнение перехода к коду функции и возврат из него). Это происходит благодаря тому, что в случае с макрокомандой препроцессор встраивает в тело программы соответствующие операторы. Однако, поскольку препроцессор заменяет каждую ссылку на макрокоманду соответствующим кодом, макрокоманды увеличивают размер вашей выполняемой программы.



ЧТ0 ВАМ НЕОБХОДИМО ЗНАТЬ


Из этого урока вы узнали, как использовать ссылки C++ для создания псевдонима или второго имени переменной. Использование ссылок может упростить функции, изменяющие значения параметров. Из урока 15 вы узнаете, что C++ позволяет вам задавать значения по умолчанию для параметров функции. При вызове функции программа может опускать значения одного или нескольких параметров и функция будет использовать значения по умолчанию. До изучения урока 15 убедитесь, что вы освоили следующие основные концепции:

Ссылка C++ является псевдонимом (или вторым именем) переменной.

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

Если вы однажды присвоили ссылке значение, вы не можете его изменить.

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

Чрезмерное использование ссылок может привести к слишком трудному для понимания программному коду.

Предыдущий урок | Следующий урок



Чтение целой строки файлового ввода


Из урока 33 вы узнали, что ваши программы могут использовать cin.getline для чтения целой строки с клавиатуры. Подобным образом объекты типа ifstream могут использовать getline для чтения строки файлового ввода. Следующая программа FILELINE.CPP использует функцию getline для чтения всех трех строк файла BOOKINFO.DAT:

#include iostream.h

#include fstream.h

void main(void)

{

ifstream input_file("BOOKINFO.DAT");

char one[64], two[64], three [64] ;

input_file.getline(one, sizeof(one)) ;

input_file.get line(two, sizeof(two));

input_file.getline(three, sizeof(three)) ;

cout one endl;

cout two endl;

cout three endl;

}

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



ЧТЕНИЕ ИЗ ВХОДНОГО ФАЙЛОВОГО ПОТОКА


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

ifstream input_file("filename.EXT");

Следующая программа FILE_IN.CPP открывает файл BOOKINFO.DAT, который вы создали с помощью предыдущей программы, и читает, а затем отображает первые три элемента файла:

#include iostream.h

#include fstream.h

void main(void)

{

ifstream input_file("BOOKINFO.DAT") ;

char one[64], two[64], three[64];

input_file one;

input_file two;

input_file three;

cout one endl;

cout two endl;

cout three endl;

}

Если вы откомпилируете и запустите эту программу, то, вероятно, предположите, что она отобразит первые три строки файла. Однако, подобно cin, входные файловые потоки используют пустые символы, чтобы определить, где заканчивается одно значение и начинается другое. В результате при запуске предыдущей программы на дисплее появится следующий вывод:

С:\ FILE_IN ENTER

учимся

программировать

на



ЧТЕНИЕ С КЛАВИАТУРЫ ЦЕЛОЙ СТРОКИ


Как вы уже знаете, при использовании cin для выполнения ввода с клавиатуры, cin использует пустые символы, такие как пробел, табуляция или возврат каретки, для определения, где заканчивается одно значение и начинается другое. Во многих случаях вы захотите, чтобы ваши программы считывали целую строку данных в символьную строку. Для этого программы могут использовать функцию cin.getline. Для использования cin.getline вам необходимо указать символьную строку, в которую будут помещаться символы, а также размер строки, как показано ниже:

cin.getline(string, 64);

Когда cin.get читает символы с клавиатуры, она не будет читать символов больше, чем может вместить строка. Удобным способом определить размер массива является использование оператора C++ sizeof, как показано ниже:

сin.getline(string, sizeof(string));

Если позже вы измените размер массива, то вам не нужно будет искать и изменять каждый оператор с cin.get, встречающийся в вашей программе. Вместо этого оператор sizeof' будет использовать корректный размер массива. Следующая программа GETLINE.CPP использует функцию cin.getline для чтения с клавиатуры строки текста:

#include iostream.h

void main(void)

{

char string[128];

cout "Введите строку текста и нажмите Enter" endl;

cin.getline(string, sizeof(string));

cout "Вы ввели: " string endl;

}

Когда вы читаете символы с клавиатуры, то, возможно, вам понадобится читать символы вплоть до и включая определенный символ. Когда такой символ будет прочитан, возможно, вы захотите завершить операцию ввода. Для выполнения подобной операции ваша программа может передать искомый символ в cin.getline. Например, следующий вызов заставляет функцию cin.getline читать строку текста, пока не встретится возврат каретки, или пока не будут прочитаны 64 символа, или пока не встретится буква Я:

cin.getline(string, 64, 'Я');

Следующая программа UNTIL_Z.CPP использует cin.getline для чтения строки текста или символов вплоть до появления буквы Я (включая и эту букву):

#include iostream.h

void main(void)

{

char string[128];

cout "Введите строку текста и нажмите Enter" endl;

cin.getline(string, sizeof(string), 'Я');

cout "Вы ввели: " string endl;

}

Откомпилируйте и запустите эту программу. Экспериментируйте с различными строками текста. Некоторые из них начинайте с буквы Я, некоторые заканчивайте буквой Я, а некоторые пусть вообще не содержат букву Я.



Чтение символьных данных


Обе предыдущие программы использовали cin для чтения целых чисел в переменные типа int. Следующая программа CIN_CHAR.CPP использует входной поток cin для чтения символов с клавиатуры. Как видите, программа читает символ в переменную типа char.

#include iostream.h

void main(void)

{

char letter;

cout "Введите любой символ и нажмите Enter: ";

cin letter;

cout "Был введен символ " letter endl;

}

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



Чтение слов с клавиатуры


Во второй части данной книги вы научитесь сохранять слова или даже строки текста в одной переменной. Там же вы узнаете, как использовать входной поток cin для чтения слов и целых строк. А сейчас можете создать свою собственную простую программу, которая читает значения типа float или long. Например, следующая программа CIN_LONG.CPP использует cin для чтения значения типа long:

#include iostream.h

void main(void)

{

long value;

cout "Введите большое число и нажмите Enter: ";

cin value;

cout "Было введено число " value endl;

}

Как и раньше, поэкспериментируйте с этой программой, вводя очень большие числа (и отрицательные тоже).

Перенаправление В/В и входной поток cin

Как вы уже знаете из урока 3, если ваши программы используют выходной поток cout, пользователь может перенаправить вывод программы с экрана дисплея в файл или на принтер. Как уже обсуждалось, выходной поток cout соответствует стандартному выводу операционной системы. Подобным образом входной поток cin соответствует стандартному вводу операционной системы. В результате, если ваша программа использует cin для выполнения операций ввода, пользователь может перенаправить ввод программы с клавиатуры на файл. В последующих уроках вы научитесь писать программы, которые читают и обрабатывают перенаправленный ввод.



Чтение ввода с клавиатуры


В этой книге ваши программы использовали выходной поток cout для отображения вывода на экран. Из данного урока вы узнаете, что C++ обеспечивает входной поток с именем cin, из которого программы могут читать информацию, введенную пользователем с клавиатуры. При использовании cin для чтения ввода с клавиатуры вы указываете одну или несколько переменных, которым cin будет присваивать входные значения. К тому времени, когда вы закончите этот урок, вы освоите следующие основные концепции:

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

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

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

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



ЧТЕНИЕ ВВОДА С КЛАВИАТУРЫ ПО ОДНОМУ СИМВОЛУ ЗА РАЗ


Точно так же, как cout предоставляет функцию cout.put для вывода символа, cin предоставляет функцию cin.get, которая позволяет вам читать один символ данных. Чтобы воспользоваться функцией cin.get, вы просто присваиваете переменной возвращаемый этой функцией символ, как показано ниже:

letter = cin.get();

Следующая программа CIN_GET.CPP выводит сообщение, в ответ на которое вам необходимо ввести Y или N. Затем она повторяет в цикле вызов cin.get для чтения символов, пока не получит Y или N:

#include iostream.h

#include ctype.h

void main(void)

{

char letter;

cout "Хотите продолжать? (Y/N): ";

do

{

letter = cin.get();

// Преобразовать к верхнему регистру

letter = toupper(letter);

} while ((letter != 'Y') (letter != 'N'));

cout endl "Вы ввели " letter endl;

}



ЧТО ТАКОЕ ЧИСТО ВИРТУАЛЬНЫЕ ФУНКЦИИ


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

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

class phone

{

public:

virtual void dial (char *number) =0; // Чисто виртуальная функция

void answer(void) { cout "Ожидание ответа" endl; }

void hangup(void) { cout "Звонок выполнен - повесить трубку" endl; }

void ring(void) { cout "Звонок, звонок, звонок" endl; }

phone(char *number) { strcpy(phone::number, number); };

protected:

char number[13];

};

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



ЧТО ТАКОЕ ПОЛИМОРФИЗМ


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

class phone

{

public:

void dial(char "number) { cout "Набор номера " number endl; }

void answer(void) { cout "Ожидание ответа" endl; }

void hangup(void) { cout "Звонок выполнен - повесить трубку" endl; }

void ring(void) { cout "Звонок, звонок, звонок" endl;)

phone(char *number) { strcpy(phone::number, number); };

private:

char number[13];

);

Следующая программа PHONEONE.CPP использует класс phone для создания объекта-телефона:

#include iostream.h

#include string.h

class phone

{

public:

void dial(char *number) { cout "Набор номера " number endl; }

void answer(void) { cout "Ожидание ответа" endl; }

void hangup(void) { cout "Звонок выполнен - повесить трубку" endl; }

void ring(void) { cout "Звонок, звонок, звонок" endl; }

phone(char *number) { strcpy(phone::number, number); };

private:

char number[13];

};

void main(void)

{

phone telephone("555-1212");

telephone.dial("212-555-1212");

}

Если вы продемонстрируете программу вашему боссу, то он или она скажет, что ваша программа не делает различий между дисковым и кнопочным телефонами, и что она не поддерживает платные телефоны, когда пользователь должен заплатить 25 центов, чтобы позвонить.


Поскольку вы знаете наследование, то примете решение породить классы touch_tone и pay_phone из класса phone, как показано ниже:

class touch_tone : phone

{

public:

void dial(char * number) { cout "Пик пик Набор номера " number endl; }

touch_tone(char *number) : phone(number) { }

};

class pay_phone : phone

{

public:

void dial(char * number)

{

cout "Пожалуйста, оплатите " amount " центов" endl;

cout "Набор номера " number endl;

}

pay_phone(char *number, int amount) : phone(number) { pay_phone::amount = amount; }

private:

int amount;

};

Как видите, классы touch_tone и pay__phone определяют свой собственный метод dial. Если вы предположите, что метод dial класса, phone основан на дисковом телефоне, то вам не потребуется создавать класс для дискового телефона. Следующая программа NEWPHONE.CPP использует эти классы для создания объектов rotary, touch_tone и pay_phone:

#include iostream.h

#include string.h

class phone

{

public:

void dial(char *number) { cout "Набор номера " number endl; }

void answer(void) { cout "Ожидание ответа" endl; }

void hangup(void) { cout "Звонок выполнен - повесить трубку" endl; }

void ring(void) { cout "Звонок, звонок, звонок" endl; }

phone(char *number) { strcpy(phone::number, number); };

protected:

char number[13];

);

class touch_tone : phone

{

public:

void dial(char *number) { cout "Пик пик Набор номера " number endl; }



touch_tone(char *number) : phone(number) { }

};

class pay_phone : phone

{

public:

void dial(char * number) { cout "Пожалуйста, оплатите " amount " центов" endl; cout "Набор номера " number endl; }

pay_phone(char * number, int amount) : phone(number) { pay_phone::amount = amount; }

private:

int amount ;

};

void main (void)

{

phone rotary("303-555-1212");

rotary.dial("602-555-1212");

touch_tone telephone("555-1212");

telephone.dial("212-555-1212");

pay_phone city_phone("555-1111", 25);

city_phone.dial("212-555-1212");

}

Если вы откомпилируете и запустите эту программу, на экране дисплея появится следующий вывод:

С:\ NEWPHONE Enter

Набор номера 602-555-1212

Пик пик Набор номера 212-555-1212

Пожалуйста, оплатите 25 центов

Набор номера 212-555-1212

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


ЧТО ТАКОЕ void main(void)


При создании программы на C++ ваш исходный файл будет содержать множество операторов. Как вы поймете в процессе изучения, порядок, в котором операторы появляются в программе, не обязательно должен совпадать с порядком, в котором операторы будут выполняться при запуске программы. Каждая программа на C++ имеет один вход, с которого начинается выполнение программы, — главную программу. В программах на C++ оператор void main(void) указывает стартовую точку вашей программы.

По мере того как ваши программы становятся больше и сложнее, вы будете делить их на несколько небольших легко управляемых частей. При этом оператор void main(void) указывает начальные (или главные) операторы программы — часть программы, которая выполняется первой.

Представление о главной программе

Исходные файлы C++ могут содержать очень много операторов. При запуске программы оператор void main(void) определяет главную программу, содержащую первый выполняемый оператор. Ваши программы на C++ должны всегда включать один и только один оператор с именем main.

При рассмотрении больших программ на C++ ищите main, чтобы определить операторы, с которых начинается выполнение программы.



ЧТО ТАКОЕ ЗАЩИЩЕННЫЕ ЭЛЕМЕНТЫ


При изучении определений базовых классов вы можете встретить элементы, объявленные как public, private и protected (общие, частные и защищенные). Как вы знаете, производный класс может обращаться к общим элементам базового класса, как будто они определены в производном классе. С другой стороны, производный класс не может обращаться к частным элементам базового класса напрямую. Вместо этого для обращения к таким элементам производный класс должен использовать интерфейсные функции. Защищенные элементы базового класса занимают промежуточное положение между частными и общими. Если элемент является защищенным, объекты производного класса могут обращаться к нему, как будто он является общим. Для оставшейся части вашей программы защищенные элементы являются как бы частными. Единственный способ, с помощью которого ваши программы могут обращаться к защищенным элементам, состоит в использовании интерфейсных функций. Следующее определение класса book использует метку protected, чтобы позволить классам, производным от класса book, обращаться к элементам title, author и pages напрямую, используя оператор точку:

class book

{

public:

book(char *, char *, int) ;

void show_book(void) ;

protected:

char title [64];

char author[64];

int pages;

};

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

Защищенные элементы обеспечивают доступ и защиту

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



ЧТО ВАМ НЕОБХОДИМО ЗНАТЬ


Из этого урока вы узнали, как создавать и компилировать программы на C++! В уроке 2 вы получите более подробный обзор операторов, которые использовались в программах, созданных в данном уроке. Вы изучите использование фигурных скобок {}, ключевых слов, таких как void, а также как научить программы направлять вывод на экран.

До изучения урока 2 убедитесь, что вы освоили следующие основные концепции:

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

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

Вы сохраняете свои программы на C++ в исходных файлах, для которых используется расширение СРР.

Компилятор преобразует операторы программы на C++ в единицы и нули — машинный язык, который понимает компьютер.

Подобно всем языкам, в C++ существует набор правил, называемых синтаксисом.

Если вы нарушаете правила синтаксиса, компилятор выводит сообщение, описывающее ошибку.

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

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

Следующий урок.


Из этого урока вы узнали несколько способов использования cout для отображения вывода на экран. Все программы, которые вы создадите в процессе изучения оставшейся части книги, будут использовать cout для отображения вывода. Из урока 4 вы узнаете, как использовать переменные внутри своих программ для хранения значений, которые могут изменяться в процессе выполнения программы. Однако до изучения урока 4 убедитесь, что вы освоили следующие основные концепции:

Выходной поток cout позволяет вам выводить символы и числа.

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

Для продвижения курсора в начало следующей строки программы могут создать новую строку, используя символ \n или модификатор endl.

Модификаторы dec, oct и hex позволяют программам выводить значения в десятичном, восьмеричном и шестнадцатеричном виде.

Используя выходной поток cerr, программы могут записать сообщения в стандартное устройство ошибок операционной системы.

С помощью модификатора setw ваши программы могут управлять шириной вывода чисел.

Предыдущий урок | Следующий урок




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

Для использования переменной в вашей программе вы должны объявить ее тип и имя.

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

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

В C++ буквы верхнего и нижнего регистров считаются разными.

Тип переменной определяет тип значения, которое переменная может содержать. Общими типами переменных являются char, int, float и long.

Комментарии повышают удобочитаемость вашей программы, поясняя ее работу. В программах на C++ комментарии начинаются с двойного слеша (//).

Предыдущий урок | Следующий урок




В этом уроке вы научились использовать входной поток cin для выполнения ввода с клавиатуры. Как вы уже знаете, если ваши программы используют cin для чтения ввода с клавиатуры, вам следует указать переменные, которым cin присваивает вводимые значения. В уроке 7 вы научитесь использовать оператор C++ if, чтобы позволить программам принимать собственные решения. Однако перед тем, как приступить к уроку 7, убедитесь, что вы освоили следующие основные концепции:

C++ предоставляет входной поток cin, который ваши программы могут использовать для чтения ввода с клавиатуры.

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

Чтобы направить ввод в переменную, вам следует использовать cin с оператором извлечения ().

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

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

Предыдущий урок | Следующий урок




Из этого урока вы узнали, как использовать оператор C++ if для выполнения условной обработки, которая позволяет вашим программам принимать собственные решения. Как вы знаете, программы могут использовать оператор if, чтобы выполнить один набор операторов, когда условие истинно, и else для указания операторов, выполняющихся программой, если условие ложно. Из урока 8 вы узнаете, как использовать итеративные операторы C++ для повторения операторов указанное число раз или до тех пор, пока выполняется определенное условие. Например, вы можете повторять один и тот же оператор 100 раз, чтобы прибавить 100 студентам тестовые очки. Однако до изучения урока 8 убедитесь, что вы освоили следующие основные концепции:

Операции сравнения C++ позволяют вашим программам проверять, равны ли два значения или нет, или одно значение больше или меньше другого.

Оператор C++ if позволяет программе проверять условия и выполнять один или несколько операторов, если условие истинно.

Оператор C++ else позволяет указать один или несколько операторов, которые выполняются, если условие, проверяемое с помощью оператора if, является ложным.

C++ представляет истину, используя любое ненулевое значение, а ложь как 0.

Логические операции C++ И () и ИЛИ (||) позволяют вашим программам проверять несколько условий.

Логическая операция НЕ (!) позволяет программам проверять условие на неистинность.

Если в операторе if или else нужно выполнить несколько операторов, то такие операторы следует расположить внутри левой и правой фигурных скобок {}.

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

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

Когда программа встречает в операторе switch вариант (case), соответствующий условию, то все последующие варианты рассматриваются как удовлетворяющие условию. Используя оператор break, вы можете указать C++ прервать оператор switch и продолжить выполнение программы с первого оператора, который следует за switch.

Предыдущий урок | Следующий урок




Итеративная обработка представляет собой способность программы повторять один или несколько операторов. В этом уроке были описаны итеративные (или циклические) операторы C++. Как вы уже знаете, оператор for позволяет вашим программам повторять один или несколько операторов заданное число раз. Используя оператор while, программы повторяют операторы до тех пор, пока указанное условие истинно. Наконец, с помощью оператора do while программы выполняют операторы, по крайней мере один раз, повторяя их, если заданное условие истинно. Из урока 9 вы узнаете, как разделить программы на небольшие легко управляемые части, называемые функциями. Однако до изучения урока 9 убедитесь, что освоили следующее:

Оператор C++ for позволяет вашим программам повторять один или более операторов заданное число раз.

Оператор for состоит из четырех частей: инициализации, проверяемого условия, операторов, которые повторяются, и приращения.

Оператор for не обязывает вас увеличивать управляющую переменную цикла именно на 1 или использовать именно приращение.

Цикл C++ while позволяет вашим программам повторять операторы, пока указанное условие истинно.

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

Оператор C++ do while позволяет вашим программам выполнять один или несколько операторов, по крайней мере один раз, и воз можно, повторять их на основании заданного условия.

Программы часто используют операторы do while для работы с меню

Если проверяемые условия в циклах, while или do while становятся ложью, программа продолжает свое выполнение с первого оператора, следующего за циклом.

Предыдущий урок | Следующий урок




Из этого урока вы узнали, как использовать функции в программах на C++. Данный урок охватил целый ряд основных понятий, таких как параметры, типы возвращаемых значений и прототипы функций. Сейчас вы можете потратить несколько больше времени на эксперименты с простыми программами. Из урока 10 вы узнаете, как изменять значения параметров внутри функций. Однако до изучения урока 10 убедитесь, что вы освоили следующие основные концепции:

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

Функции могут возвращать значение вызвавшей функции. При этом вы должны указать тип возвращаемого функцией значения (int, char и т. д.) до имени функции, в противном случае вы должны предварять имя функции словом void.

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

C++ должен знать тип возвращаемого значения и количество и тип параметров, которые получает функция. Если определение функции следует за использованием функции, вы должны поместить прототип функции в начале исходного файла.

Предыдущий урок | Следующий урок




Из данного урока вы узнали, как изменить значение параметра внутри функции. Для этого ваши функции должны использовать указатели. Сначала вы можете найти указатели слишком сложными. Из урока 14 вы узнаете, как использовать ссылки C++ , которые упрощают процесс изменения параметров внутри функции. Однако, поскольку многие программисты С используют указатели для изменения параметров, вам необходимо знать и такой вариант программирования.

Из урока 11 вы выясните, как функции библиотеки этапа выполнения, обеспечиваемые компилятором C++ , могут ускорить программирование, позволяя быстро разрабатывать сложные программы. Однако до изучения урока 11 убедитесь, что вы освоили следующие основные Концепции:

Пока вы не используете указатели или ссылки C++ , функция не может изменить значение параметра.

Когда ваша программа передает параметр в функцию, C++ помещает копию значения параметра во временный участок памяти, называемый стеком. Любые изменения, которые функция осуществляет над параметром, влияют только на эту копию, расположенную в стеке.

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

Используя оператор адреса C++ (), ваши программы могут передать адрес переменной в функцию.

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

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

Предыдущий урок | Следующий урок




Библиотека этапа выполнения C++ предоставляет мощный набор функций, которые вы можете использовать в ваших программах. Не жалейте времени, чтобы изучить документацию по библиотеке этапа выполнения, поставляемой с вашим компилятором. Выясните смысл функций, имеющихся в библиотеке этапа выполнения. Преимущество этих функций состоит в том, что вы избавляетесь от значительного объема программирования. В уроке 12 вы научитесь обращаться с локальными переменными и областью видимости (участок вашей программы, где известно имя переменной). Прежде чем перейти к уроку 12, убедитесь, что вы освоили следующие основные концепции:

Библиотека этапа выполнения представляет собой набор функций, обеспечиваемых компилятором для ваших программ.

Для использования функции из библиотеки этапа выполнения вы должны указать ее прототип.

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

В дополнение к библиотеке этапа выполнения многие компиляторы C++ предоставляют функции API (интерфейс прикладных программ) для выполнения определенных задач, например программирования графики или мультимедиа.

Предыдущий урок | Следующий урок




Из этого урока вы узнали, как объявлять локальные переменные внутри функции. Как только ваши функции выполняют более или менее существенную работу, им требуются локальные переменные. В этом уроке представлены также глобальные переменные, чьи имена и значения известны на протяжении всей программы. Поскольку они могут приводить к трудно обнаруживаемым ошибкам, лучше избегать использования глобальных переменных, если только это возможно. Из урока 13 вы узнаете, как C++ позволяет объявлять две или несколько функций с одним и тем же именем, но с разными параметрами и типами возвращаемых значений. Перегружая подобным образом имена функций, вы упрощаете использование функций. Прежде чем перейти к уроку 13, убедитесь, что вы изучили следующие основные концепции:

Локальные переменные представляют собой переменные, объявленные внутри функции.

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

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

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

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

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

Предыдущий урок | Следующий урок




Конструкторы и деструкторы представляют собой специальные функции класса, которые ваша программа автоматически вызывает при создании или уничтожении объекта. Большинство программ используют конструктор для инициализации элементов данных класса. Простые программы, создаваемые сейчас вами, вероятно, не потребуют использования деструктора. Из урока 24 вы узнаете, как перегружать операторы. Другими словами, вы можете переопределить символ плюс таким образом, что он будет добавлять содержимое одной строки к другой. Как вы уже знаете, тип (например, char, float и int) определяет набор значений, которые может хранить переменная, и набор операций, которые ваши программы могут выполнять над этой переменной. Когда вы определяете класс, вы по существу определяете тип. C++ позволяет вам указать, как ведут себя операторы с данным типом. До изучения урока 24 убедитесь, что освоили следующие основные концепции:

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

Конструктор не имеет возвращаемого значения, но вы не указываете ему тип void. Вместо этого вы просто не указываете возвращаемое значение вообще.

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

C++ позволяет вам перегружать конструкторы и разрешает использовать значения по умолчанию для параметров.

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

Предыдущий урок | Следующий урок




Перегрузка операторов — это возможность назначать новый смысл операторам при использовании их с определенным классом. Используя перегрузку операторов, вы можете повысить удобочитаемость ваших программ и облегчить их понимание, выражая операции класса более понятным образом. Из урока 25 вы узнаете, как разделить данные между объектами с помощью элемента static и как использовать методы класса, когда никакие объекты класса не объявляются. До изучения урока 25 убедитесь, что вы освоили следующее:

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

Когда вы перегружаете оператор, перегрузка действует только для класса, в котором он определяется. Если программа использует оператор с неклассовыми переменными (например, переменными типа int или float), используется стандартное определение оператора.

Чтобы перегрузить оператор класса, используйте ключевое слово C++ operator для определения метода класса, который C++ вызывает каждый раз, когда переменная класса использует оператор.

C++ не позволяет вашим программам перегружать оператор выбора элемента (.), оператор указателя на элемент (.*), оператор разрешения области видимости (::) и условный оператор сравнения (?:).

Предыдущий урок | Следующий урок




Из этого урока вы узнали, что, если предварять элемент данных класса ключевым словом static, все объекты данного класса могут совместно использовать этот элемент. Когда элемент данных является общим, ваши программы могут обращаться к его значению, даже если объекты этого класса не существуют. Подобно этому, если ваши программы предваряют общий метод класса ключевым словом static, они могут использовать эту функцию для операций, которые не включают объекты класса. Из урока 26 вы узнаете, как использовать наследование для построения объекта из одного или нескольких уже существующих объектов. Использование наследования для создания новых объектов может сэкономить огромные усилия, затрачиваемые на программирование. До изучения урока 26 убедитесь, что освоили следующие основные концепции:

Когда вы объявляете элемент класса как static, то такой элемент может совместно использоваться всеми объектами данного класса.

После того как ваша программа объявляет элемент класса как static, она должна вне определения класса объявить глобальную переменную, соответствующую совместно используемому элементу класса.

Если вы объявляете элемент как public и static, ваша программа может использовать такой элемент, даже если объекты данного класса не существуют. Для обращения к этому элементу ваша программа должна использовать оператор глобального разрешения, например class_name::member_name.

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

Предыдущий урок | Следующий урок




Из этого урока вы узнали, что наследование в C++ позволяет вам строить /порождать) новый класс из существующего класса. Строя таким способом один класс из другого, вы уменьшаете объем программирования, что, в свою очередь, экономит ваше время. Из урока 27 вы узнаете, что C++ позволяет вам порождать класс из двух или нескольких базовых классов. Использование нескольких базовых классов для порождения класса представляет собой множественное наследование. До изучения урока 27 убедитесь, что освоили следующие основные концепции:

Наследование представляет собой способность производить новый класс из существующего базового класса.

Производный класс — это новый класс, а базовый класс — существующий класс.

Когда вы порождаете один класс из другого (базового класса), производный класс наследует элементы базового класса.

Для порождения класса из базового начинайте определение производного класса ключевым словом class, за которым следует имя класса, двоеточие и имя базового класса, например class dalmatian: dog.

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

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

Чтобы обеспечить производным классам прямой доступ к определенным элементам базового класса, в то же время защищая эти элементы от оставшейся части программы, C++ обеспечивает защищенные {protected) элементы класса. Производный класс может обращаться к защищенным элементам базового класса, как будто они являются общими. Однако для оставшейся части программы защищенные элементы эквивалентны частным.

Если в производном и базовом классе есть элементы с одинаковым именем, то внутри функций производного класса C++ будет использовать элементы производного класса. Если функциям производного класса необходимо обратиться к элементу базового класса, вы должны использовать оператор глобального разрешения, например base class:: member.

Предыдущий урок | Следующий урок




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

Множественное наследование является способностью порожденного класса наследовать характеристики нескольких базовых классов.

Для порождения класса из нескольких базовых после имени нового класса и двоеточия вы указываете имена базовых классов, разделяя их запятыми, например class cabbit: public cat, public rabbit.

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

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

Предыдущий урок | Следующий урок




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

Использование в ваших программах на C++ друзей позволяет одному классу обращаться к частным элементам другого класса напрямую, используя оператор точку.

Для объявления одного класса другом (friend) другого класса вы должны внутри определения этого другого класса указать ключевое слово friend, за которым следует имя первого класса.

После объявления класса другом по отношению к другому классу, все функции-элементы класса-друга могут обращаться к частным элементам этого другого класса.

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

При объявлении дружественных функций вы можете получить синтаксические ошибки, если неверен порядок определений классов. Если необходимо сообщить компилятору, что идентификатор представляет имя класса, который программа определит позже, вы можете использовать оператор такого вида class class_name;.

Предыдущий урок | Следующий урок




Как вы уже знаете, использование шаблонов функций уменьшает объем программирования, позволяя компилятору C++ генерировать операторы для функций, которые отличаются только типами возвращаемых значений и параметров. Из урока 30 вы узнаете, как использовать шаблоны для создания типонезависимых, или общих, классов. До изучения урока 30 убедитесь, что вы освоили следующие основные концепции:

Шаблоны функций позволяют вам объявлять типонезависимые, или общие, функции.

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

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

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

Если функция требует несколько типов, шаблон просто назначает каждому типу уникальный идентификатор, например Т, T1 и Т2. Позже в процессе компиляции компилятор C++ корректно назначит типы, указанные вами в прототипе функции.

Предыдущий урок | Следующий урок




Из этого урока вы узнали, что шаблоны классов помогут вам избавиться от дублирования кода программы, если вам необходимы объекты похожих классов, которые отличаются только типом. Поскольку шаблоны классов могут быть сложными, они могут вас смутить. Когда вы определяете ваш класс, начните с определения, как будто бы вы создаете класс для конкретного типа. После того как вы полностью опишете класс, определите какие элементы необходимо изменить, чтобы работать с объектами различных типов. Теперь замените типы этих элементов такими символами, как, например, Т, Т1, Т2 и т.д.

Программы, представленные в данном уроке, использовали оператор C++ new для динамического (во время выполнения программы) распределения памяти для массива. В уроке 31 вы подробно ознакомитесь с оператором new. Прежде чем перейти к уроку 31, убедитесь, что вы изучили следующее:

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

Для создания шаблона класса предварите определение класса ключевым словом template и символами типов, например Т и T1.

Далее вы должны предварить определение каждой функции класса таким же оператором с ключевым словом template. Кроме того, укажите типы шаблона между левой и правой угловыми скобками, а выражение в угловых скобках поместите между именем класса и оператором разрешения области видимости, например class_nameT,T1::function_name.

Для создания класса с использованием шаблона укажите имя класса и замещающие значения для типов между левой и правой угловыми скобками, например class_nameint, long object.

Предыдущий урок | Следующий урок




Из этого урока вы узнали, что ваши программы могут распределять память динамически во время выполнения из неиспользуемой памяти, называемой свободной памятью, используя для этих целей оператор new. Выделяя подобным образом память динамически, программы могут удовлетворять ваши изменяющиеся запросы без редактирования и перекомпиляции самой программы. Из урока 32 вы узнаете, как управлять распределением свободной памяти, и что делают операторы new, если они не могут удовлетворить запрос на распределение памяти. Прежде чем перейти к уроку 32, убедитесь, что вы изучили следующее:

Способность выделять память динамически во время выполнения снимает с ваших программ зависимость от фиксированных размеров массивов.

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

Если оператор new не может выделить требуемую вашей программой память, он возвращает NULL-указатель, который содержит значение 0.

Каждый раз, когда ваши программы распределяют память динамически с использованием оператора new, они должны проверять значение возвращаемого оператором new указателя, чтобы определить, не равен ли он NULL, что указывает на невозможность выделения памяти.

Используя указатель на массив, ваши программы могут обращаться к памяти, выделенной с помощью оператора new.

Оператор new выделяет память из блока неиспользуемой памяти, называемой свободной памятью.

В зависимости от вашей операционной системы и модели памяти компилятора размер свободной памяти может быть различным. В среде MS-DOS свободная память может быть ограничена 64 Кбайт.

Если вашей программе больше не нужна выделенная память, она должна освободить ее (вернуть в свободную память), используя для этого оператор delete.

Предыдущий урок | Следующий урок




По мере того как ваши программы становятся более сложными, вы будете выделять память в процессе выполнения, используя оператор new. Из этого урока вы узнали, как изменить поведение оператора new, сначала определяя функцию-обработчик, которую вызывает ваша программа, если new не может удовлетворить запрос на память, а затем с помощью перегрузки самого оператора new. Из урока 33 вы узнаете новые способы использования входного потока cm и выходного потока соut для усовершенствования возможностей ввода и вывода ваших программ. Прежде чем перейти к уроку 33, убедитесь, что вы изучили следующее:

Если оператор new не может удовлетворить запрос на память, то по умолчанию он присваивает значение NULL соответствующему указателю.

Если вашим программам необходима другая обработка в том случае, когда new не может удовлетворить запрос на память, ваши программы могут определить свои собственные обработчики. Используя функцию set_new_handler, программа может заставить new вызвать вашу функцию, если невозможно удовлетворить запрос на память.

C++ позволяет вашим программам перегружать операторы new и delete. Однако, прежде чем это сделать, вы должны иметь четкое представление о свободной памяти (куче) и функциях библиотеки этапа выполнения, которые ею манипулируют.

Предыдущий урок | Следующий урок




Каждая созданная вами на C++ программа будет, вероятно, использовать cin или cout для выполнения операций ввода и вывода. Этот урок посвящен некоторым манипуляторам В/В и функциям, которые вы можете использовать с потоками cin и cout. По мере усложнения ваших программ они часто будут сохранять информацию в файлах. Из урока 34 вы узнаете, как в C++ выполнять операции файлового ввода и вывода. Прежде чем приступить к изучению урока 34, убедитесь, что вы освоили следующие основные концепции:

cin и cout являются объектами (переменными) классов istream и ostream, которые определены в заголовочном файле iostream.h. А если так, они предоставляют функции, которые ваши программы могут вызывать для решения определенных задач.

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

Функция cout. fill позволяет вашим программам указать символ, который cout будет использовать для заполнения пустого пространства устанавливаемого с помощью cout.width или setw.

Манипулятор setprecision позволяет вашим программам управлять количеством цифр, выводимых справа от десятичной точки для значений с плавающей точкой.

Функции cin.get и cout.put позволяют вашим программам вводить или выводить один символ.

Функция cin.getline позволяет вашим программам читать строку текста с клавиатуры.

Предыдущий урок | Следующий урок




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

Заголовочный файл fstream.h определяет классы ifstream и ofstream, с помощью которых ваша программа может выполнять операции файлового ввода и вывода.

Для открытия файла на ввод или вывод вы должны объявить объект типа ifstream или ofstream, передавая конструктору этого объекта имя требуемого файла.

После того как ваша программа открыла файл для ввода или вывода, она может читать или писать данные, используя операторы извлечения () и вставки ().

Ваши программы могут выполнять ввод или вывод символов в файл или из файла, используя функции get и put.

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

Большинство программ читают содержимое файла, пока не встретится конец файла. Ваши программы могут определить конец файла с помощью функции eof.

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

Если вашим программам необходимо вводить или выводить такие данные, как структуры или массивы, они могут использовать методы read и write.

Если ваша программа завершила работу с файлом, его следует закрыть с помощью функции close.

Предыдущий урок | Следующий урок




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

Помещение параметров в стек и переход к функции и из нее вносит издержки, из-за которых ваша программа выполняется немного медленнее.

Ключевое слово inline заставляет компилятор C++ заменять вызов функции эквивалентной последовательностью операторов, которые бы выполняла эта функция. Поскольку встроенные операторы избавляют от издержек на вызов функции, программа будет выполняться быстрее.

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

Ключевое слово asm позволяет вам встраивать операторы языка ассемблера в программы на C++.

Предыдущий урок | Следующий урок




Чтобы увеличить количество приложений, поддерживаемых вашей программой, C++ позволяет использовать аргументы командной строки. Из урока 37 вы узнаете, как с помощью макрокоманд и констант можно упростить ваше программирование или создать более удобочитаемый код. Однако, прежде чем перейти к уроку 37, убедитесь, что вы освоили следующие основные концепции:

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

Чтобы позволить вашим программам обращаться к командной строке C++ передает функции main два параметра: argc и argv.

Параметр argc содержит количество аргументов командной строки.

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

В зависимости от вашего компилятора программа может обращаться к третьему параметру main с именем env, который представляет собой массив указателей на символьные строки, содержащие переменные среды.

Предыдущий урок | Следующий урок




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

Макрокоманды и именованные константы облегчают чтение ваших программ, заменяя сложные выражения и числовые константы смысловыми именами.

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

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

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

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

Предыдущий урок | Следующий урок




Полиморфизм представляет собой способность объекта изменять форму во время выполнения программы. В этом уроке рассмотрены шаги, которые вам необходимо выполнить для создания полиморфных объектов. Из урока 39 вы узнаете, как использовать исключительные ситуации в C++ для обеспечения надежности вашей программы. Прежде чем приступить к уроку 39 убедитесь, что вы освоили следующие основные концепции:

Полиморфный объект может изменять форму во время выполнения программы.

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

В базовом для полиморфного объекта классе вы должны определить одну или несколько функций как виртуальные (virtual).

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

Для создания полиморфного объекта вам необходимо создать указатель на объект базового класса.

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

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

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

Предыдущий урок | Следующий урок




Исключительные ситуации предназначены для упрощения и усовершенствования обнаружения и обработки ошибочных ситуаций в ваших программах. Для проверки и обнаружения исключительных ситуаций ваши программы должны использовать операторы try, catch и throw. Ваши знания исключительных ситуаций зависят от опыта программирования на C++. Прежде чем продолжить программировать на C++, убедитесь, что вы освоили следующие основные концепции:

Исключительная ситуация представляет собой неожиданную ошибку в вашей программе.

Ваши программы должны обнаруживать и обрабатывать (реагировать на) исключительные ситуации.

В программах вы определяете исключительную ситуацию как класс.

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

Вы должны разместить оператор catch сразу же после оператора try, чтобы определить, какая именно исключительная ситуация имела место (если она вообще была).

C++ сам не генерирует исключительные ситуации. Ваши программы генерируют исключительные ситуации с помощью оператора throw.

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

Если ваши программы используют исключительные ситуации, вы можете указать в прототипе функции, что эта функция способна генерировать исключительную ситуацию.

При чтении документации по библиотеке этапа выполнения обращайте внимание на то, что некоторые функции способны генерировать исключительные ситуации.

Если ваша программа генерирует, но не улавливает (и не обрабатывает) исключительную ситуацию, C++ будет вызывать стандартный обработчик исключительной ситуации.

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

Предыдущий урок



ЧТО ВНУТРИ iostream.h


Начиная с урока 1, каждая написанная вами на C++ программа включала заголовочный файл iostream.h. Этот файл содержит определения, позволяющие вашим программам использовать cout для выполнения вывода и cin для выполнения ввода. Более точно, этот файл определяет классы istream и ostream (входной поток и выходной поток), a cin и соut являются переменными (объектами) этих классов. Выберите время, чтобы напечатать файл iostream.h. Он находится в подкаталоге INCLUDE. Определения в этом файле достаточно сложны. Однако если вы пройдете по файлу медленно, то обнаружите, что большинство определений являются просто определениями классов и констант. Внутри файла вы найдете объявления переменных cin и cout.



ЧТО ВЫ ДОЛЖНЫ ЗНАТЬ


В этом уроке обсуждались некоторые общие вопросы, с которыми вы столкнетесь в программах на C++. Из Урока 3 вы узнаете, как использовать cout для вывода символов, целых чисел и значений с плавающей точкой. Вы также узнаете, как форматировать вывод. До изучения урока 3 убедитесь, что вы освоили следующие основные концепции:

Большинство программ на C++ начинаются с оператора #include, который предписывает компилятору включить содержимое заданного заголовочного файла в программу.

Заголовочные файлы содержат определения, предоставляемые компилятором, которые ваши программы могут использовать.

Исходный файл может состоять из множества операторов; оператор void main(void) указывает начало главной программы, которая содержит первый выполняемый оператор программы.

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

Большинство программ на C++ используют выходной поток cout для вывода информации на экран; однако, используя операторы переназначения В/В операционной системы, вы можете перенаправить вывод cout в файл, устройство (например, принтер) или даже сделать его входом другой программы.

Предыдущий урок | Следующий урок



Циклы for C++ поддерживают составные операторы


Из урока 7 вы узнали, что если программы выполняют несколько операторов внутри if или else, то такие операторы следует сгруппировать внутри левой и правой фигурных скобок. Это же относится и к нескольким операторам в цикле for. Следующая программа ADD1_100.CPP зацикливает числа от 1 до 100, выводя и добавляя каждое число в общий итог:

#include iostream.h

void main(void)

{

int count;

int total = 0;

for (count = 1; count = 100; count++)

{

cout "Прибавляю " count " к " total;

total = total + count;

cout " получаю " total endl;

}

}

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



Дополнительные возможности cin и cout


На всем протяжении этой книги вы использовали выходной поток cout для вывода информации на экран дисплея. Аналогично, многие из ваших программ использовали входной поток cin для чтения информации с клавиатуры. Оказывается, cin и cout представляют собой классовые объекты, определяемые и создаваемые с помощью заголовочного файла iostream.h. Как объекты cin и cout поддерживают различные операторы и операции. Из данного урока вы узнаете, как расширить возможности ввода и вывода, используя функции, встроенные в классы cin и cout. К концу этого урока вы освоите следующие основные концепции:

Заголовочный файл iostream.h содержит определения классов, которые вы можете проанализировать, чтобы лучше понять потоковый ввод/вывод.

Используя метод cout.width, ваши программы могут управлять шириной вывода.

Используя метод cout.fill, ваши программы могут заменить пустые выходные символы (табуляцию и пробелы) некоторым определенным символом.

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

Для вывода и ввода по одному символу за один раз ваши программы могут использовать потоковые методы cout.put и cin.get.

Используя метод cin.getline, ваши программы могут вводить целую строку за один раз.

Почти любая создаваемая вами на C++ программа будет использовать cout или cin для выполнения операций В/В (ввода/вывода). Выберите время для экспериментов с программами из этого урока.



ДОСТУП К argv И argc


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

С:\ COPY SOURCE.DOC TARGET.DOC ENTER

В данном случае командная строка указывает команду (COPY) и два аргумента (имя файлов SOURCE. DOC и TARGET. DOC). Чтобы разрешить вашей программе доступ к командной строке, C++ передает два параметра в функцию main:

void main(int argc, char *argv[])

Первый параметр argc содержит количество элементов в массиве argv. Например, в случае предыдущей команды COPY параметр argc должен содержать значение 3 (он включает имя команды и два аргумента). Следующая программа SHOWARGC.CPP использует параметр argc для вывода количества аргументов командной строки:

#include iostream.h

void main(int argc, char *argv[])

{

cout "Количество аргументов командной строки равно " argc endl;

}

Выберите время для эксперимента с этой программой, вызывая ее с разным количеством параметров, как показано ниже:

С:\ SHOWARGC А В С ENTER

Количество аргументов командной строки равно 4

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

С:\ SHOWARGC "Это один аргумент" ENTER

Количество аргументов командной строки равно 2

36. Массив argv указывает аргументы командной строки.

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

Следующая программа SHOWARGV.CPP использует оператор for для вывода элементов массива argv (командная строка программы). Программа запускается с первого элемента массива (имя программы) и затем выводит каждый элемент, пока значение переменной цикла не станет больше, чем argc:

#include iostream.h

void main(int argc, char *argv[])


{

int i;

for (i = 0; i argc; i++) cout "argv[" i "] содержит " argv[i] endl;

}

Откомпилируйте и запустите эту программу, используя командную строку, подобную следующей:

С:\ SHOWARGV А В С ENTER

argv[0] содержит SHOWARGV.EXE

argv[l] содержит А

argv[2] содержит В

argv[3] содержит С

Доступ к аргументам командной строки

Для увеличения количества задач, выполняемых программой, C++ позволяет вашей программе обращаться к аргументам командной строки, используя два параметра, которые C++ передает в main. Первый параметр argc содержит количество аргументов командной строки (включая имя программы). Второй параметр argv представляет собой массив указателей на символьные строки. Каждая символьная строка соответствует аргументу командной строки. Чтобы обратиться к аргументам командной строки, измените заголовок функции main, как показано ниже:

void main(int argc, char *argv[])


ДОСТУП К ПЕРЕМЕННЫМ СРЕДЫ ОПЕРАЦИОННОЙ СИСТЕМЫ


Как вы знаете, большинство операционных систем позволяют вам определять переменные среды, к которым ваши программы могут обращаться для определения разных параметров, таких как командный путь. Например, если вы используете среду MS-DOS, вы устанавливаете или выводите переменные среды с помощью команды SET. В зависимости от типа вашего компилятора вы можете обращаться к переменным среды из вашей программы, используя третий параметр main с именем env. Подобно параметру argv, параметр env представляет собой указатель на массив указателей на символьные строки. Также, подобно argv, C++ завершает этот массив символом NULL. Если ваш компилятор поддерживает параметр env, вы можете изменить заголовок функции main, как показано ниже:

void main(int argc, char *argv[], char *env[])

Следующая программа SHOWENV.CPP выполняет цикл по элементам массива env для вывода переменных среды программы:

#include iostream.b

void main(int argc, char *argv[], char *env[])

{

while (*env) cout *env++ endl;

}

Как видите, программа просто выполняет цикл по элементам массива env, пока не встретит указатель NULL, который указывает последнюю запись массива. Если вы откомпилируете и запустите эту программу, она выведет ваши переменные среды, как показано ниже:

С:\ SHOWENV ENTER

ТЕМР=С:\WINDOWS\TEMP

PROMPT=$p$g

COMSPEC=C:\WINDOWS\COMMAND.СОМ

РАТН=С:\WINDOWS;С:\DOS

Доступ к переменным среды

В зависимости от типа компилятора, ваши программы могут обращаться к переменным среды операционной системы, используя третий параметр функции main с именем env. Подобно параметру argv, параметр env представляет собой массив указателей на символьные строки, каждый из которых указывает переменную среды. Чтобы обратиться к переменным среды, используя параметр env, измените заголовок функции main следующим образом:

void main(int argc, char *argv[], char *env[])



ДРУГИЕ ОПЕРАТОРЫ С++


В этом уроке описаны обычные арифметические операции C++, а также операции увеличения и уменьшения. В программах на C++ вы можете встретить одну или несколько операций, перечисленных в табл. 5.2:

Таблица 5.2. Операции C++, которые вы можете встретить в программах.

Операция

Функция

%

Взятие по модулю или остаток; возвращает остаток целочисленного деления



Другие специальные символы


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

~ Дополнение; инвертирует биты значений
Побитовое И
| Побитовое включающее ИЛИ
^ Побитовое исключающее ИЛИ
Сдвиг влево; сдвигает биты значения влево на указанное количество разрядов
Сдвиг вправо; сдвигает биты значения вправо на указанное количество разрядов

Таблица 3.1. Специальные символы для использования с cout.

Символ

Назначение

Сигнальный (или звонок) символ

Символ возврата

V

Символ перевода страницы

\n

Символ новой строки

Возврат каретки (не перевод строки)

\t

Символ горизонтальной табуляции

\v

Символ вертикальной табуляции

\\

Символ обратный слеш

\?

Знак вопроса

\'

Одинарные кавычки

\"

Двойные кавычки

\0

Нулевой символ

\000

Восьмеричное значение, например \007

\xhhhh

Шестнадцатеричное значение, например \xFFFF

Замечание: При использовании специальных символов, перечисленных в табл. 3.1, вам следует располагать их внутри одинарных кавычек, если вы используете данные символы сами по себе, например '\n', или внутри двойных кавычек, если вы используете их внутри строки, например "Привem\nMup!".

Следующая программа SPECIAL.CPP использует специальные символы сигнала (\а) и табуляции (\t) для выдачи звука на встроенный динамик компьютера и затем выводит слова Звонок Звонок Звонок, разделенные табуляцией:

#include iostream.h

void main(void)

{

cout "3вонок\a\tЗвонок\a\tЗвонок\a";

}



Если имена глобальных и локальных переменных конфликтуют


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

Однако могут быть ситуации, когда вам необходимо обратиться к глобальной переменной, чье имя конфликтует с именем локальной переменной. В таких случаях ваши программы могут использовать глобальный оператор разрешения С++ (::), если вы хотите использовать глобальную переменную. Например, предположим, что у вас есть глобальная и локальная переменные с именем number. Если ваша функция хочет использовать локальную переменную number, она просто обращается к этой переменной, как показано ниже:

number = 1001; // обращение к локальной переменной

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

::number = 2002; // Обращение к глобальной переменной

Следующая программа GLOBLOCA.CPP использует глобальную переменную number. В дополнение к этому функция show_numbers использует локальную переменную с именем number. Эта функция использует оператор глобального разрешения для обращения к глобальной переменной:

#include iostream.h int number = 1001; // Глобальная переменная

void show_numbers(int number)

{

cout "Локальная переменная number" " содержит " number endl;

cout "Глобальная переменная number" " содержит " ::number endl;

}

void main(void)

{

int some_value = 2002;

show_numbers(some_value) ;

}

Когда вы откомпилируете и запустите эту программу, на вашем экране появится следующий вывод:


С:\ GLOBLOCA ENTER

Локальная переменная number содержит 2002

Глобальная переменная number содержит 1001

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

О глобальных переменных

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


Файловые операции В/В в C++


По мере усложнения ваших программ они будут сохранять и получать информацию, используя файлы. Если вы знакомы с файловыми манипуляциями в языке С, вы сможете использовать подобные методы и в C++. Кроме того, как вы узнаете из этого урока, C++ предоставляет набор классов файловых потоков, с помощью которых можно очень легко выполнять операции ввода и вывода (В/В) с файлами. К концу данного урока вы освоите следующие основные концепции:

Используя выходной файловый поток, вы можете писать информацию в файл с помощью оператора вставки ().

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

Для открытия и закрытия файла вы используете методы файловых классов.

Для чтения и записи файловых данных вы можете использовать операторы вставки и извлечения, а также некоторые методы файловых классов.

Многие программы, которые вы создадите в будущем, будут интенсивно использовать файлы. Выберите время для экспериментов с программами, представленными в данном уроке. И вы обнаружите, что в C++ выполнять файловые операции очень просто.



Функции, изменяющие элементы структуры


Как вы знаете, если функция изменяет параметр, вам следует передавать этот параметр в функцию с помощью адреса. Если функция изменяет элемент структуры, вы должны передавать эту структуру в функцию с помощью адреса, Для передачи переменной типа структуры с помощью адреса вы просто предваряете имя переменной оператором адреса C++ (), как показано ниже:

some_function(worker);

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

pointer_variable-member = some_value;

Например, следующая программа CHG_MBR.CPP передает структуру типа employee в функцию с именем get_employee_id, которая запрашивает у пользователя идентификационный номер служащего и затем присваивает этот номер элементу структуры employee_id. Чтобы изменить элемент, функция работает с указателем на структуру:

#include iostream.h

#include string.h

struct employee

{

char name[64];

long employee_id;

float salary;

char phone[10];

int office_number;

};

void get_employee_id(employee *worker)

{

cout "Введите номер служащего: ";

cin worker-employee_id;

}

void main(void)

{

employee worker;

// Копировать имя в строку strcpy(worker.name, "Джон Дой");

get_employee_id(worker) ;

cout "Служащий: " worker, name endl;

cout "Номер служащего: " worker.employee_id endl;

}

Как видите, внутри main программа передает переменную worker типа структуры в функцию get_employee_id с помощью адреса. Внутри функции gel_employee_id значение, введенное пользователем, присваивается элементу employee_id с помощью следующего оператора:

cin worker-employee_id;

Работа с указателями на структуры

Если функция изменяет элемент структуры, вызвавшая программа должна передать структуру в функцию с помощью адреса. Функция, в свою очередь, использует указатель на структуру. Для обращения к элементу структуры функции следует использовать следующий формат:

value = variable-member;

variable-other_member = some_value;



ФУНКЦИИ, КОТОРЫЕ НЕ ВОЗВРАЩАЮТ ЗНАЧЕНИЕ


Если функция не возвращает значение, вам необходимо предварить имя функции типом void. В противном случае вы должны предварять имя функции типом возвращаемого функцией значения, например, int, float, char и т. д. Чтобы возвратить значение вызвавшей функции, функция использует оператор return. Когда ваша программа встречает оператор return, выполнение функции завершается и указанное значение возвращается вызвавшей функции. Возможны ситуации, когда вы встретите оператор return в функции, которая не возвращает значение:

return;

В этом случае функция имеет тип void (не возвращает значение) и оператор return просто завершает выполнение функции.

Замечание: Если операторы появляются в функции после оператора return они не будут выполняться. Как уже обсуждалось выше, если ваша программа встречает оператор return в функции, то возвращается соответствующее значение, функция заканчивается и выполнение программы продолжается с первого оператора, следующего за вызовом функции.



ФУНКЦИИ МОГУТ ВОЗВРАЩАТЬ РЕЗУЛЬТАТ ВЫЗВАВШЕЙ ФУНКЦИИ


Функция должна выполнять определенную задачу для вашей программы. В большинстве случаев функции будут выполнять некоторые типы вычислений. Затем функция возвратит свой результат вызвавшей функции. Когда функция возвращает значение, вы должны сообщить C++ тип значения, например int, float, char т. д. Чтобы информировать C++ о типе возвращаемого функцией значения, просто поставьте перед именем функции соответствующий тип. Например, следующая функция add_values складывает два своих целочисленных параметра и возвращает результат типа int вызвавшей программе:

int add_values (int а, int b)

{

int result;

result=а+b;

return (result);

}

В данном случае слово int, появляющееся перед именем функции, указывает тип возвращаемого значения функции. Функции используют оператор return для возврата значения вызвавшей функции. Когда ваша программа встречает оператор return, она возвращает заданное значение и завершает выполнение функции, возвращая управление вызвавшей программе. В программе вы можете использовать возвращаемое значение, как показано ниже:

result=add_values (1, 2);

В данном случае программа присваивает возвращаемое функцией значение переменной result. Ваша программа может также сразу же напечатать возвращаемое функцией значение с помощью cout, как показано ниже:

cout "Сумма значений равна " add_values (500, 501) endl;

Предыдущая реализация функции add_values использовала три оператора, чтобы было легче понять смысл функции. Однако вы можете сократить функцию до единственного оператора return, как показано ниже:

int add_values (int a, int b)

{

return (a+ b);

}

Следующая программа ADDVALUE.CPP использует функцию add_values для сложения нескольких значений:

#include iostream.h

int add_values (int a, int b)

{

return (a+ b);

}

void main (void)

{

cout " 100 + 200 = " add_values(100, 200) endl;


cout " 500 + 501 = " add_values(500, 501) endl;


cout "-1 + 1 = " add_values(-1, 1) endl;

}

Выберите время для эксперимента с этой программой, изменяя значения, которые программа передает в функцию. Вы могли бы попытаться передать в функцию большие значения, например 20000 и 30000. Как и можно предложить, выполнение функции, возвращающей значение типа int, приведет к ошибке переполнения.

Не все функции возвращают значение типа int. Следующая функция average_value возвращает среднее двух целочисленных значений, которое может быть дробным, например 3.5:

float average_value(int a, int b)

{

return( (a + b) / 2.0);

}

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


ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ


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

int some_global_variable; --- Объявление глобальной переменной

void main(void)

{

// Здесь должны быть операторы программы

}

Следующая программа GLOBAL. CPP использует глобальную переменную именем number. Каждая функция в программе может использовать (или изменять) значение глобальной переменной. В данном случае каждая функция выводит текущее значение этой переменной, а затем увеличивает это значение на единицу:

#include iostream.h

int number = 1001;

void first_change(void)

(

cout "значение number в first_cbange " number endl;

number++;

}

void second_change(void)

{

cout "значение number в second_change " number endl;

number++;

}

void main(void)

{

cout "значение number в main " number endl;

number++;

first_change () ;

second_change();

}

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



Хранение информации с помощью массивов и структур


Как вы уже знаете, переменная может хранить значение определенного типа. В программах на C++, которые вы создали при изучении первых двух частей этой книги, переменные хранили только одно значение. По мере увеличения сложности ваших программ в некоторых ситуациях вам потребуется работать с несколькими значениями одновременно. Например, ваша программа может работать со 100 тестовыми очками, 30 стоимостью акций или фамилиями и адресами 5000 служащих вашей компании. В этой части вы узнаете, как использовать разные типы данных C++ для хранения множества значений внутри одной и той же переменной. Как вы узнаете, использовать одну переменную для хранения множества значений очень удобно.

Урок 16. Хранение значений в массивах.

Урок 17. Символьные строки.

Урок 18. Хранение связанной информации в структурах.

Урок 19. Объединения.

Урок 20. Указатели.

Предыдущая часть | Следующая часть



Хранение связанной информации в структурах


Из урока 16 вы узнали, что C++ позволяет хранить в массиве связанную информацию одного и того же типа. Вы уже выяснили, что группировка связанных значений в массив очень удобна. В большинстве случаев программам необходимо группировать связанную информацию разного типа. Например предположим, что ваша программа работает с информацией о служащих. Она должна отслеживать данные о фамилии, возрасте, окладе, адресе, номере служащего и т. д. Для хранения этой информации программе потребуются переменные типа char, int, float, а также символьные строки.

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

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

Структура состоит из одной или нескольких частей данных, называемых элементами.

Для определения структуры внутри программы следует указать имя структуры и ее элементы.

Каждый элемент структуры имеет тип, например char, int и float, и имя каждого элемента должно быть уникальным.

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

Для изменения элементов структуры внутри функции ваши программы должны передать структуру в функцию с помощью адреса.

Ваше умение понимать структуры и работать с ними облегчит использование объектно-ориентированных классов C++ в части 4. Выберите время для эксперимента с программами, представленными в этом уроке.



Хранение значений в массивах


Как вы уже знаете, ваши программы во время выполнения хранят информацию в переменных. До сих пор каждая переменная в программе хранила только одно значение в каждый момент времени. Однако в большинстве случаев программам необходимо хранить множество значений, например 50 тестовых очков, 100 названий книг или 1000 имен файлов. Если вашим программам необходимо хранить несколько значений, они должны использовать специальную структуру данных, называемую массивом. Для объявления массива необходимо указать имя, тип массива и количество значений, которые массив будет хранить. Этот урок описывает, как программы объявляют массивы, а затем сохраняют и обращаются к информации, содержащейся в массиве. К концу данного урока вы освоите следующие основные концепции:

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

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

Все элементы внутри массива должны быть одного и того же типа, например, int, float или char.

Для сохранения значения внутри массива вам следует указать номер элемента массива, в котором вы хотите сохранить свое значение.

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

При объявлении массива программы могут использовать оператор присваивания для инициализации элементов массива.

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

Программы на C++ широко используют массивы. Когда в уроке 17 вы начнете работать с символьными строками (например, название книги, имя файла и т. д.), вы будете оперировать массивами символов.



ИНИЦИАЛИЗАЦИЯ МАССИВА ПРИ ОБЪЯВЛЕНИИ


Как вы уже знаете, C++ позволяет вашим программам инициализировать переменные при объявлении. То же верно и для массивов. При объявлении массива вы можете указать первоначальные значения, поместив их между левой и правой фигурными скобками, следующими за знаком равенства. Например, следующий оператор инициализирует массив values:

int values[5] = { 100, 200, 300, 400, 500 };

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

float salaries[3] = { 25000.00. 35000.00, 50000.00 };

Если вы не указываете первоначальное значение для какого-либо элемента массива, большинство компиляторов C++ будут инициализировать такой элемент нулем. Например, следующее объявление инициализирует первые три из пяти элементов массива:

int values[5] = { 100, 200, 300 };

Программа не инициализирует элементы values[3] и values[4]. В зависимости от вашего компилятора, эти элементы могут содержать значение 0. Если вы не указываете размер массива, который вы инициализируете при объявлении, C++ распределит достаточно памяти, чтобы вместить все определяемые элементы. Например, следующее объявление создает массив, способяый хранить четыре целочисленных значения:

int numbers[] = { 1, 2, 3, 4 };



ИНИЦИАЛИЗАЦИЯ СИМВОЛЬНОЙ СТРОКИ


Как вы уже знаете из урока 16, C++ позволяет вам инициализировать массивы при объявлении. Символьные строки C++ не являются исключением. Для инициализации символьной строки при объявлении укажите требуемую строку внутри двойных кавычек, как показано ниже:

char title[64] = "Учимся программировать на языке C++";

Если количество символов, присваиваемое строке, меньше размера массива, большинство компиляторов C++ будут присваивать символы NULL остающимся элементам строкового массива. Как и в случае с массивами других типов, если вы не указываете размер массива, который инициализируете при объявлении, компилятор C++ распределит достаточно памяти для размещения указанных букв и символа NULL:

char title[] = "Учимся программировать на языке C++";

Следующая программа INIT_STR.CPP инициализирует символьную строку при объявлении:

#include iostream.h

void main(void)

{

char title[64] = "Учимся программировать на языке C++";

char lesson[64] = "Символьные строки";

cout "Книга: " title endl;

cout "Урок: " lesson endl;

}

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



ИСКЛЮЧИТЕЛЬНЫЕ СИТУАЦИИ И КЛАССЫ


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

class string

{

public:

string(char *str);

void fill_string(*str);

void show_string(void);

int string_length(void);

class string_empty { } ;

class string_overflow {};

private:

int length;

char string[255];

};

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

try

{

some_string.fill_string(some_long_string);

};

catch (string::string_overflow)

{

cerr "Превышена длина строки, символы отброшены" endl;

}



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


Как вы знаете, большинство команд, вводимых вами в ответ на системную подсказку, позволяют включать дополнительную информацию, такую как имя файла. Например, при использовании команды MS-DOS COPY для копирования содержимого одного файла во второй файл вы указываете в командной строке имена обоих файлов. Аналогично, если ваш компилятор основан на командной строке, вы должны включать имя вашего исходного файла при вызове компилятора. В этом уроке рассмотрены способы, с помощью которых ваши программы на C++ обращаются к аргументам командной строки. К концу данного урока вы освоите следующие основные концепции:

Программы на C++ трактуют аргументы командной строки как параметры функции main.

По традиции C++ передает два (иногда три) параметра в main, которые в большинстве программ называются argc и argv.

Параметр argc содержит количество аргументов командной строки, передаваемых в вашу программу.

Параметр argv представляет собой массив указателей на символьные строки, каждая из которых соответствует одному параметру командной строки.

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

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


Следующая программа FILESHOW.CPP использует аргументы командной строки для вывода содержимого указанного пользователем файла на экран. Например, чтобы использовать программу FILESHOW для вывода содержимого файла AUTOEXEC.BAT из корневого каталога, ваша командная строка становится следующей:

C: \ FILESHOW \AUTOEXEC.BAT Enter

Следующие операторы реализуют программу FILESHOW.CPP. Эта программа начинается с проверки параметра argc, чтобы убедиться, что пользователь указал файл в командной строке. Если пользователь включает имя файла параметр argc будет содержать значение 2. Далее программа открывает и выводит содержимое файла, используя методы, которые вы изучали в уроке 34. Как видите, если программа не может открыть указанный файл, она выводит сообщение об ошибке и завершается:

#include iostream.h

#include fstream.h

#include stdlib.h

void main(int argc, char *argv[])

{

char line[256];

if (argc 2)

{

cerr "Вы должны указать имя файла" endl;

exit(1);

}

ifstream input_file(argv[1]) ;

if (input_file.fail()) cerr "Ошибка открытия BOOKINPO.DAT" endl;

else

{

while ((! input_file.eof()) (! input_file.fail()))

{

input_file.getline(line, sizeof(line));

if (! input_file.fail()) cout line endl;

}

}

}



ИСПОЛЬЗОВАНИЕ cout


Как вы уже знаете, cout представляет собой класс, который содержит несколько разных методов. Следующие программы иллюстрируют использование некоторых методов, которые ваши программы могут применять для форматирования вывода. Из урока 3 вы узнали, что манипулятор setw позволяет вашим программам указать минимальное количество символов, которое может занять следующее выходное значение:

#include iostream.h

#include iomanip.h

void main(void)

{

cout "Мое любимое число" setw(3) 1001 endl;

cout "Мое любимое число" setw (4) 1001 endl;

cout "Мое любимое число" setw (5) 1001 endl;

cout "Мое любимое число" setw(6) 1001 endl;

}

Подобным образом метод cout.width позволяет вам указать минимальное количество символов, которое будет использовать сои/для вывода следующего значения. Следующая программа COUTWIDT.CPP использует функцию cout.width для выполнения работы, аналогичной той, которую выполняет setw, что и показано ниже:

#include iostream.h

#include iomanip.h

void main (void)

{

int i;

for (i = 3; i 7; i++)

{

cout "Мое любимое число";

cout. width (i);

cout 1001 endl;

}

}

Если вы откомпилируете и запустите вашу программу, на экране дисплея появится следующий вывод:

С:\ COUTWIDT ENTER

Мое любимое число1001

Мое любимое число 1001

Мое любимое число 1001

Мое любимое число 1001

Подобно манипулятору setw, ширина, выбираемая с помощью функции cout.width, действует только для следующего выходного значения.



ИСПОЛЬЗОВАНИЕ cout ДЛЯ ОТОБРАЖЕНИЯ ВЫВОДА НА ЭКРАН


Все программы на C++, созданные вами в уроке 1, выводили сообщения на экран. Чтобы вывести сообщение, программы использовали cout и двойной знак "меньше" (), как показано ниже:

cout "Привет, C++!";

Слово cout представляет собой выходной поток, который C++ назначает на стандартное устройство вывода операционной системы. По умолчанию операционная система назначает стандартное устройство вывода на экран дисплея. Чтобы вывести сообщение на экран, вы просто используете двойной символ "меньше" (называемый оператором вставки) с выходным потоком cout. Из урока 3 вы узнаете, что можно использовать оператор вставки для передачи символов, чисел и других знаков на экран.

Представление о выходном потоке cout

Вы уже знаете, что программы на C++ используют выходной поток cout для вывода сообщений на экран. При использовании cout для вывода сообщений представляйте cout в виде потока символов, которые операционная система отображает на экране. Другими словами, порядок, в котором ваша программа посылает символы в cout, определяет порядок символов, которые будут появляться на экране. Например, для следующих операторов программы:

cout "Это сообщение появляется первым,";

cout " а за ним следует настоящее сообщение.";

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

Это сообщение появляется первым, а за ним следует настоящее сообщение.

Оператор вставки () называется так, потому что позволяет вашей программе вставлять символы в выходной поток.

Вы уже знаете, что выходной поток cout по умолчанию соответствует вашему экрану. Другими словами, когда ваши программы посылают вывод в cout, вывод появляется на экране. Однако, используя операторы переназначения вывода операционной системы, вы можете послать вывод программы на принтер или в файл. Например, следующая команда предписывает MS-DOS направить вывод программы FIRST.EXE на принтер, а не на экран:

С:\ FIRST PRN ENTER

Как вы узнаете из Урока 3, с помощью cout в C++ можно выводить символы, целые числа, например 1001, и числа с плавающей точкой, например 3.12345. Из Урока 8 вы узнаете, что в C++ существует также входной поток с именем cin, который ваши программы могут использовать для чтения информации, вводимой с клавиатуры.



ИСПОЛЬЗОВАНИЕ cout ДЛЯ ВЫВОДА ЧИСЕЛ


До сих пор созданные вами программы использовали сом/ для вывода символьных строк (букв и чисел, взятых в кавычки). Теперь вы узнаете, что сом/ можно также использовать для вывода чисел. Следующая программа 1001.СРР выводит число 1001 на ваш экран:

#include iostream.h

void main(void)

{

cout 1001;

}

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

С:\ 1001 ENTER

/b>

Далее отредактируйте программу и измените оператор cout, чтобы вывести число 2002, как показано ниже:

cout 2002;

Кроме отображения целых чисел (чисел без десятичной точки), сом/также позволяет вашим программам отображать числа с плавающей точкой, например 1.2345. Следующая программа FLOATING.CPP использует сом/для вывода числа 0.12345 на экран:

#include iostream.h

void main(void)

{

cout 0.12345;

}

Как и ранее, откомпилируйте и запустите эту программу. На вашем экране появится следующий вывод:

С:\ FLOATING ENTER

0.12345



ИСПОЛЬЗОВАНИЕ ФУНКЦИЙ БИБЛИОТЕКИ ЭТАПА ВЫПОЛНЕНИЯ


Из урока 9 вы узнали, что до того, как ваши программы смогут вызвать функцию, компилятор C++ должен узнать определение или прототип функции. Поскольку функции библиотеки этапа выполнения не определены в вашей программе, вы должны указать прототип для каждой библиотечной функции, которую намерены использовать. Для упрощения использования библиотечных функций компилятор C++ предоставляет заголовочные файлы, содержащие корректные прототипы. Таким образом, вашим программам необходимо просто включить требуемый заголовочный файл с помощью оператора #include, а затем вызвать необходимую функцию. Например, следующая программа SHOWTIME.CPP будет использовать функции библиотеки этапа выполнения time и ctime для вывода текущей системной даты и времени. Прототипы этих двух функций библиотеки этапа выполнения содержатся в заголовочном файле time.h:

#include iostream.h

#include time.h // Для функций библиотеки этапа выполнения

void main(void)

{

time_t system_time;

system_time = time(NULL);

cout "Текущее системное время " ctime(system_time) endl;

}

Когда вы откомпилируете и запустите эту программу, на вашем экране появятся текущие системные дата и время:

С:\ SHOWTIME ENTER

Текущее системное время Mon Jan 01 16:13:51 1996

Как видите, программа использует функции time и ctime. В случае функции ctime программа передает адрес переменной system_time, используя оператор адреса, описанный в уроке 10. Для использования этих функций вам просто следует включить заголовочный файл time.h в начало вашего исходного файла.

Подобным образом следующая программа SQRT.CPP использует функцию sqrt для возврата квадратного корня нескольких значений. Прототип функции sqrt находится в заголовочном файле math.h:

#include iostream.h

#include math.h // Содержит прототип sqrt

void main(void)

{

cout "квадратный корень 100.0 равен " sqrt(100.0) endl;


cout "Квадратный корень 10.0 равен " sqrt (10.0) endl;

cout "квадратный корень 5.0 равен " sqrt(5.0) endl;

}

Наконец, программа SYSCALL. CPP использует функцию system, прототип которой определяется в заголовочном файле stdlib.h. Функция system обеспечивает легкий способ выполнения вашей программой команды операционной системы, такой как "DIR", или другой программы:

#include stdlib.h

void main(void)

{

system("DIR");

}

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


ИСПОЛЬЗОВАНИЕ ИМЕНОВАННЫХ КОНСТАНТ


Именованная константа — это просто имя, которому вы присваиваете постоянное значение (константу). Такая константа в отличие от значения переменной не может изменяться по мере выполнения программы. Вы создаете именованную константу, используя директиву препроцессора #define (специальную инструкцию для препроцессора компилятора). Например, следующий оператор определяет именованную константу CLASS_SIZE как значение 50:

#define CLASS_SIZE 50

Чтобы отличить именованную константу от переменной, большинство программистов используют для именованных констант буквы верхнего регистра. Например, следующая программа CONSTANT.CPP определяет и выводит именованную константу CLASS_SIZE:

#include iostream.h

#define CLASS_SIZE 50 // Число студентов в классе

void main(void)

{

cout "Константа CLASS_SIZE равна " CLASS_SIZE endl;

}

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

Замечание: Предыдущее определение константы не заканчивается точкой с запятой. Если вы поставите точку с запятой в конце определения, препроцессор включит ее в ваше определение. Например, если вы в директиве #define предыдущей программы поставите точку с запятой после значения 50, препроцессор в дальнейшем каждый экземпляр константы CLASS_SIZE заменит значением 50 с точкой с запятой (50;), что, очень вероятно, приведет к синтаксической ошибке.

Что такое директивы препроцессора

Прежде чем приступить к компиляции программы, компилятор C++ запускает специальную программу, которая называется препроцессором. Препроцессор ищет в программе строки, начинающиеся с символа #, например #include или #define. Если препроцессор, например, встречает директиву #include, он включает указанный в ней файл в ваш исходный файл, как будто бы вы сами печатали содержимое включаемого файла в вашем исходном коде. Каждая программа, которую вы создали при изучении данной книги, использовала директиву #include, чтобы заставить препроцессор включить содержимое заголовочного файла iostream.h в ваш исходный файл. Если препроцессор встречает директиву #define, он создает именованную константу или макрокоманду. В дальнейшем, если препроцессор встречает имя константы или макрокоманды, он заменяет это имя значением, указанным в директиве #define.


Если вы определяете константы в своих программах, C++ не ограничивает вас в использовании только цифровых значений. Вы можете также использовать константы для хранения символьных строк и значений с плавающей точкой. Например, следующая программа BOOKINFO.CPP использует директиву #define для создания трех констант, которые содержат информацию об этой книге:

#include iostream.h

#define TITLE "Учимся программировать на языке C++"

#define LESSON 37

#define PRICE 22.95

void main(void)

{

cout "Название книги: " TITLE endl;

cout "Текущий урок: " LESSON endl;

cout "Цена: $" PRICE endl;

}

Если вы откомпилируете и запустите эту программу, на экране дисплея появится следующий вывод:

С:\ BOOKINFO ENTER

Название книги: Учимся программировать на языке C++

Текущий урок: 37

Цена: $22.95

Использование #define для создания именованных констант

Для улучшения читаемости ваших программ заменяйте числовые значения в исходном коде константами со смысловыми именами. Для определения именованной константы ваши программы должны использовать директиву препроцессора #define. Размещайте свои константы в верхней части вашего исходного файла. Кроме того, чтобы отличать константы от переменных, большинство программистов для имен констант используют буквы верхнего регистра.

Например, следующая директива #define создает константу с именем SECONDS_PER_HOUR

#define SECONDS_PER_HOUR 3600

Во время компиляции программы препроцессор C++ будет заменять каждый экземпляр имени SECONDS_PER_HOUR числовым значением 3600. Обратите внимание, что определение константы не заканчивается точкой с запятой. Если вы поставите после 3600 точку с запятой, препроцессор C++ в дальнейшем заменит каждый экземпляр имени SECONDS_PER_HOUR его значением с точкой с запятой (3600;), что, очень вероятно, приведет к синтаксической ошибке.


ИСПОЛЬЗОВАНИЕ ИМЕНОВАННЫХ КОНСТАНТ ДЛЯ УПРОЩЕНИЯ ИЗМЕНЕНИЯ КОДА


Кроме того, что именованные константы делают вашу программу легче для восприятия, они еще и облегчают модификацию программ. Например, следующий фрагмент кода несколько раз ссылается на число 50 (количество студентов в классе):

#include iostream.h

void main(void)

{

int test_score8[50];

char grades[50];

int student;

for (student = 0; student 50; student++) get_test_score(student);

for (student =0; student 50; student++) calculate_grade(student);

for (student =0; student 50; student++) print_grade(student) ;

}

Предположим, например, что количество студентов в классе увеличилось до 55. В этом случае вы должны отредактировать предыдущую программу, чтобы заменить каждый экземпляр значения 50 значением 55. В следующей программе применен другой подход, она использует именованную константу CLASS_SIZE:

#include iostream.h

#define CLASS_SIZE 50

void main(void)

{

int test_scores[CLASS_SIZE] ;

char grades[CLASS_SIZE] ;

int student;

for (student = 0; student CLASS_SIZE; student++) get_test_score(student);

for (student = 0; student CLASS_SIZE; student++) calculate_grade(student) ;

for (student = 0; student CLASS_SIZE; student++) print_grade(student);

}

В данном случае для изменения количества студентов во всей программе вам необходимо изменить только одну строку, которая содержит директиву #define, определяющую эту константу:

#define CLASS_SIZE 55



Использование индексной переменной


Если ваши программы используют массив, обычной операцией является использование индексной переменной для обращения к элементам массива. Например, предположим, что переменная / содержит значение 3, следующий оператор присваивает значение 400 элементу values[3J:

values[i] = 400;

Следующая программа SHOWARRA.CPP использует индексную переменную i внутри цикла for для вывода элементов массива. Цикл for инициализирует i нулем, так что программа может обращаться к элементу values[O]. Цикл for завершается, когда i больше 4 (последний элемент массива):

#include iostream.h

void main (void)

{

int values[5]; // Объявление массива int i;

values[0] = 100;

values[1] = 200;

values[2] = 300;

values[3] = 400;

values[4] = 500;

cout "Массив содержит следующие значения" endl;

for (i = 0; i 5; i++) cout values [i] ' ';

}

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

for (i = 4; i = 0; i--) cout values [i] ' ';

В данном случае программа будет выводить элементы массива от большего к меньшему.



Использование исключительных ситуаций C++ для обработки ошибок


После того как вы создали и отладили (удалили ошибки) несколько программ, вы уже способны предвидеть ошибки, которые могут встретиться в программе. Например, если ваша программа читает информацию из файла, ей необходимо проверить, существует ли файл и может ли программа его открыть. Аналогично, если ваша программа использует оператор new для выделения памяти, ей необходимо проверить и отреагировать на возможное отсутствие памяти. По мере увеличения размера и сложности ваших программ вы обнаружите, что необходимо включить много таких проверок по всей программе. Из этого урока вы узнаете, как использовать исключительные ситуации C++ для упрощения проверки и обработки ошибок. К концу данного урока вы освоите следующие основные концепции:

Исключительная ситуация (exception) представляет собой неожиданное событие — ошибку — в программе.

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

Чтобы заставить ваши программы следить за исключительными ситуациями, необходимо использовать оператор C++ try.

Для обнаружения определенной исключительной ситуации ваши программы используют оператор C++ catch.

Для генерации исключительной ситуации при возникновении ошибки ваши программы используют оператор C++ throw.

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

Некоторые (старые) компиляторы не поддерживают исключительные ситуации C++.



ИСПОЛЬЗОВАНИЕ ЭЛЕМЕНТОВ ДАННЫХ ИСКЛЮЧИТЕЛЬНОЙ СИТУАЦИИ


В предыдущих примерах ваши программы, используя оператор catch, могли определить, какая именно исключительная ситуация имела место, и отреагировать соответствующим образом. В идеале, чем больше информации об исключительной ситуации могут получить ваши программы, тем лучше они смогут отреагировать на ошибку. Например, в случае с исключительной ситуацией file_open_error вашей программе необходимо знать имя файла, который вызвал ошибку. Аналогично, для файловых исключительных ситуаций file_read_error или file_write_error программа, возможно, захочет узнать расположение байта, на котором произошла ошибка. Чтобы сохранить подобную информацию об исключительной ситуации, ваши программы могут просто добавить элементы данных в класс исключительной ситуации. Если в дальнейшем ваша программа сгенерирует исключительную ситуацию, она передаст эту информацию функции обработки исключительной ситуации в качестве параметра, как показано ниже:

throw file_open_error(source);

throw file_read_error(344);

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

class file_open_error

{

public:

file_open_error(char *filename) { strcpy(file_open_error::filename, filename); }

char filename[255] ;

};



Использование элементов с атрибутами public static, если объекты не существуют


Как вы только что узнали, при объявлении элемента класса как static этот элемент совместно используется всеми объектами данного класса. Однако возможны ситуации, когда программа еще не создала объект, но ей необходимо использовать элемент. Для использования элемента ваша программа должна объявить его как public и static. Например, следующая программа USЕ_MBR.CPP использует элемент page_count из класса book_series, даже если объекты этого класса не существуют:

#include iostream.h

#include string.h

class book_series

{

public:

static int page_count;

private:

char title [64];

char author[64];

float price;

};

int book_series::page_count;

void main(void)

{

book_series::page_count = 256;

cout "Текущее значение page_count равно " book_series::page_count endl;

}

В данном случае, поскольку класс определяет элемент класса page_count как public, программа может обратиться к этому элементу класса, даже если объекты класса book_series не существуют.



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


Структура позволяет вашим программам группировать информацию, называемую элементами, в одной переменной. Чтобы присвоить значение элементу или обратиться к значению элемента, используйте оператор C++ точку (.). Например, следующие операторы присваивают значения различным элементам переменной с именем worker тута employee;

worker.employee_id = 12345;

worker.salary = 25000.00;

worker.оffice_number = 102;

Для обращения к элементу структуры укажите имя переменной, за которым следует точка и имя элемента. Следующая программа EMPLOYEE.CPP иллюстрирует использование структуры типа employee:

#include iostream.h

#include string.h

void main(void)

{

struct employee

{

char name [64];

long employee_id;

float salary;

char phone[10];

int office_number;

} worker;

// Копировать имя в строку strcpy(worker.name, "Джон Дой");

worker.employee_id = 12345;

worker.salary = 25000.00;

worker.office_number = 102;

// Копировать номер телефона в строку strcpy(worker.phone, "555-1212") ;

cout "Служащий: " worker.name endl;

cout "Телефон: " worker.phone endl;

cout "Номер служащего: " worker.employee_id endl;

cout "Оклад: " worker.salary endl;

cout "Офис: " worker.office_number endl;

}

Как видите, присваивание целому элементу и элементу с плавающей точкой очень просто. Программа использует оператор присваивания, чтобы присвоить значение соответствующему элементу. Однако обратите внимание на использование функции strcpy для копирования символьной строки в элементы name и phone. Если вы не инициализируете элементы при объявлении переменной типа данной структуры, вы должны копировать символьные строки в символьно-строковые элементы.

Объявление переменных структуры

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

variable.member = some_value;

some_variable = variable.other_member;



Использование классов C++


Объектно-ориентированное программирование фокусируется на сущностях (объектах), из которых состоит система. Например, у вас может быть объект-файл или объект-служащий и т.д. Каждый объект содержит связанные с ним данные, такие как имя файла или служащего, номер служащего и, возможно, оклад. Таким образом, объекты подобны структурам C++. Однако объекты включают также набор операций, которые ваши программы выполняют над объектами. В случае объекта-файла, вы можете печатать, удалять или даже копировать файл. Аналогично, в случае объекта-служащего вы можете напечатать данные, продвигать по службе или, возможно, даже уволить объект. C++ использует класс для хранения данных объекта и функций, которые оперируют этими данными. Эта часть рассматривает классы C++ более подробно. Уроки данной части:

Урок 21. Знакомство с классами C++.

Урок 22. Частные и общие данные.

Урок 23. Конструктор и деструктор.

Урок 24. Перегрузка операторов.

Урок 25. Статические функции и элементы данных.

Предыдущая часть | Следующая часть



Использование ключевого слова inline


При объявлении функции внутри программы C++ позволяет вам предварить имя функции ключевым словом inline. Если компилятор C++ встречает ключевое слово inline, он помещает в выполнимый файл (машинный язык) операторы этой функции в месте каждого ее вызова. Таким образом, можно улучшить читаемость ваших программ на C++, используя функции, и в то же время увеличить производительность, избегая издержек на вызов функций. Следующая программа INLINE.CPP определяет функции тах и min как inline:

#include iostream.h

inline int max(int a, int b)

{

if (a b) return(a);

else return(b) ;

}

inline int min(int a, int b)

{

if (a b) return(a);

else return(b);

}

void main(void)

{

cout "Минимум из 1001 и 2002 равен " min(1001, 2002) endl;

cout "Максимум из 1001 и 2002 равен " max(1001, 2002) endl;

}

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

О встроенных функциях

Если компилятор C++ перед определением функции встречает ключевое слово inline, он будет заменять обращения к этой функции (вызовы) на последовательность операторов, эквивалентную выполнению функции. Таким образом ваши программы улучшают производительность, избавляясь от издержек на вызов функции и в то же время выигрывая в стиле программы, благодаря использованию функций.