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

         

Следите за ошибками переполнения


Если ваши программы выполняют ввод с использованием cin, остерегайтесь возможных ошибок, возникающих при вводе пользователем неверного числа. Например, запустите программу FIRSTCIN, которую вы только что создали. Когда программа запросит вас ввести ваше любимое число, введите число 1000000 и нажмите ENTER. При этом программа не сможет отобразить число 1000000 в качестве введенного значения. Вместо этого возникнет ошибка переполнения, так как 1000000 превышает наибольшее значение, которое может хранить тип int.

Если вы внимательно рассмотрите программу FIRSTCIN. CPP, то обратите внимание, что cin присваивает введенное число переменной типа int. Как вы узнали из урока 4, переменные типа int могут хранить значения только в диапазоне от -32768 до 32767. Поскольку переменная типа int не может вместить значение 1000000, возникает ошибка. Запустите программу еще несколько раз, вводя отрицательные и положительные числа. Обратите внимание на ошибки, которые возникают, если вы выходите за допустимые пределы значений для той переменной, в которую cin помещает ввод.



СЛЕДИТЕ ЗА ОШИБКАМИ ПЕРЕПОЛНЕНИЯ ПРИ АРИФМЕТИЧЕСКИХ ОПЕРАЦИЯХ


Из урока 4 вы узнали, что, если вы присваиваете переменной значение, которое не входит в диапазон значений для данного типа переменной, возникает ошибка переполнения. При выполнении арифметических операций необходимо помнить о возможности возникновения ошибок переполнения. Например, следующая программа MATHOVER.CPP умножает 200 на 300 и присваивает результат переменной типа int. Однако, поскольку результат умножения (60000) превышает наибольшее возможное значение для типа int (32767), возникает ошибка переполнения:

#include iostream.h

void main(void)

{

int result;

result = 200 * 300;

cout "200 * 300 = " result endl;

}

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

С:\ MATHOVER ENTER

200 * 300 = -5536



Слова, которые нельзя использовать для имен переменных


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

Таблица 4.2. Ключевые слова C++.

asm

auto

break

case

catch

char

class

const

default

delete

do

double

else

enum

extern

float

friend

goto

if

inline

int

long

new

operator

protected

public

register

return

short

signed

sizeof

static

switch

template

this

throw

try

typedef

union

unsigned

void

volatile

while

continue

for

private

struct

virtual

Почему ваши программы используют переменные

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



Смысловые имена переменных


Каждая создаваемая вами переменная должна иметь уникальное имя. Чтобы сделать свои программы более легкими для чтения и понимания, следует использовать смысловые имена переменных. Например, следующий оператор объявляет три переменных с именами х, y и z:

int х, у, z;

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

int student_age, test_score, grade;

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

float MonthlySalary, IncomeTax;



СОКРЫТИЕ ИНФОРМАЦИИ


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

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

class employee

{

public:

char name [64];

long employee_id;

float salary;

void show_employee(void);

}

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


class some_class

{

public:

int some_variable;

void initialize_private(int, float); //——— Общие элементы


void show_data(void);

private:

int key_value; //————————————— Частные элементы


float key_number;

}

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

some_class object; // Создать объект

object.some_variable = 1001;

object.initialize_private(2002, 1.2345);

object.show_data()

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

Как правило, вы будете защищать элементы класса от прямого доступа к ним делая их частными. При этом программы не могут непосредственно присваивать значения таким элементам, используя оператор точку. Вместо того чтобы присвоить значение, программа должна вызвать метод класса. Предотвращая прямой доступ к элементам данных, вы, таким образом, можете гарантировать, что им всегда будут присваиваться допустимые значения. Например, предположим что объект nuclear_reactor вашей программы использует переменную с именем melt_down, которая всегда должна содержать значение в диапазоне от 1 до 5. Если элемент melt_down является общим, программа может непосредственно обратиться к элементу, изменяя его значение произвольным образом:

nuclear_reactor.melt_down = 101

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

int nuke::assign_meltdown(int value)

{

if ((value 0) (value = 5))

{

melt_down = value;



return(0); // Успешное присваивание

} elsereturn(-1); // Недопустимое значение

}

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

Общие и частные элементы

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


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


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

private:

static int shared_value;

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

int class_name::shared_value;

Следующая программа SHARE_IT.CPP определяет класс book_series, совместно использующий элемент page_count, который является одинаковым для всех объектов (книг) класса (серии). Если программа изменяет значение этого элемента, изменение сразу же проявляется во всех объектах класса:

#include iostream.h

#include string.h

class book_series

{

public:

book_series(char *, char *, float);

void show_book(void);

void set_pages(int) ;

private:

static int page_count;

char title[64];

char author[ 64 ];

float price;

};

int book_series::page__count;

void book_series::set_pages(int pages)

{

page_count = pages;

}

book_series::book_series(char *title, char *author, float price)

{

strcpy(book_series::title, title);

strcpy(book_series::author, author);

book_series::price = price;

}

void book_series:: show_book (void)

{

cout "Заголовок: " title endl;

cout "Автор: " author endl;

cout "Цена: " price endl;

cout "Страницы: " page_count endl;

}

void main(void)


{

book_series programming( "Учимся программировать на C++", "Jamsa", 22.95);

book_series word( "Учимся работать с Word для Windows", "Wyatt", 19.95);

word.set_pages(256);

programming.show_book ();

word.show_book() ;

cout endl "Изменение page_count " endl;

programming.set_pages(512);

programming.show_book();

word.show_book();

}

Как видите, класс объявляет page_count как static int. Сразу же за определением класса программа объявляет элемент page_count как глобальную переменную. Когда программа изменяет элемент page_count, изменение сразу же проявляется во всех объектах класса book_series.

Совместное использование элементов класса

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


СОЗДАНИЕ И ИСПОЛЬЗОВАНИЕ ВАШИХ ПЕРВЫХ ФУНКЦИЙ


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

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

Таблица 9. Примеры смысловых имен функций.

Имя функции

Назначение функции

Print_test_scores

Печатать тестовые очки класса

Accounts_payable

Обработать счета компании

Get_user_name

Запрос имени пользователя

Print_document

Напечатать указанный документ

Calculate_income_tax

Определить подоходный налог пользователя

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

тип_возврата имя_функции (список_параметров)

{ объявления_переменных;

операторы;

}

Рассмотрите, например, как структура этой функции соответствует следующей программе main:

void main (void) //----------- тип имя (список_параметров)

{

int count; //---------------------------объявления_переменных;

for (count = 0; count 10; count++) cout count ' '; //----- Оператор

}

Следующие операторы определяют функцию с именем show_message, которая выводит сообщение на экран, используя cout.

void show_message (void)

{

cout "Привет, учусь программировать на C++" endl;

}

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


#include iostream.h

void show_message (void)

{

cout "Привет, учусь программировать на C++" endl;

}

void main (void)

{

cout "Перед вызовом функции" endl;

show_message ();

cout "Вернулись из функции" endl;

}

Вы уже знаете, что выполнение программы всегда начинается внутри main. Внутри main следующий оператор (вызов функции) вызывает функцию show_message:

show_message ();

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

С: \SHOW_MSG ENTER

Перед вызовом функции

Привет, учусь программировать на C++

Вернулись из функции

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

#include iostream.h

void show_message (void)

{

cout "Привет, учусь программировать на C++" endl;

}

void main (void)

{

cout "Перед вызовом функции" endl;

show_message ();

cout "Вернулись из функции" endl;

}

В данном случае программа выполняет первый оператор в main, которой выводит сообщение для пользователя, что программа собирается вызвать функцию. Далее программа встречает вызов функции и запускает выполнение операторов в show_messsage. После того как программа выполнит единственный оператор функции, она возвращается обратно в main и продолжает свое выполнение с оператора, непосредственно следующего за вызовом функции. В этом случае программа выводит сообщение, извещая пользователя о том, что она возвратилась из функции, и после этого заканчивает свою работу. Следующая программа TWO__MSGS.CPP использует две функции -show_title и show_lesson для вывода информации об этой книге:



#include iostream.h

void show_title (void)

{

cout "Книга: Учимся программировать на C++" endl;

}

void show_lesson (void)

{

cout "Урок: Знакомство с функциями" endl;

}

void main (void)

{

show_title ();

show_lesson ();

}

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

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

Вызов функции

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


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

function_name();

Если программа передает информацию (параметры) в функцию, она размещает эту информацию внутри круглых скобок, разделяя ее запятыми:

payroll(employee_name, employee_id, salary);

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


СОЗДАНИЕ ОБРАБОТЧИКА ДЛЯ ОПЕРАЦИЙ СО СВОБОДНОЙ ПАМЯТЬЮ


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

#include iostream.h

void main (void)

{

char *pointer;

do

{

pointer = new char[1000];

if (pointer 1= NULL) cout "Выделено 1000 байт" endl;

else cout "Свободной памяти нет " endl;

} while (pointer);

}

Как видите, программа просто выполняет цикл, пока new не присвоит указателю значение NULL. Если вы хотите, чтобы new выполнил другие действия (что-нибудь отличное от тупого возвращения значения NULL), когда он не может удовлетворить запрос на память, то сначала вам следует определить функцию, которую должна вызывать ваша программа, если памяти недостаточно для удовлетворения запроса. Например, следующая функция end_pro-gram выводит на экран сообщение, а затем использует функцию библиотеки этапа выполнения exit для завершения программы:

void end_program(void)

{

cout "Запрос на память не может быть удовлетворен" endl;

exit(l);

}

Чтобы заставить C++ вызывать функцию end_program, если new не может удовлетворить запрос на память, вам необходимо вызвать функцию set_new_handler, указав ей функцию end_program в качестве параметра, как показано ниже:

set_new_handler(end_program);

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

#include iostream.h

#include stdlib.h // Прототип exit

#include new.h // Прототип set_new_handler

void end_program(void)

{

cout "Запрос на память не может быть удовлетворен" endl;


exit(l);

}

void main(void)

{

char* pointer;

set_new_handler(end_program);

do

{

pointer = new char[10000];

cout "Выделено 10000 байт" endl;

} while (1);

}

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


СОЗДАНИЕ ПОЛИМОРФНОГО ОБЪЕКТА-ТЕЛЕФОНА


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

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

class phone

{

public:

virtual 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];

};

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

phone *poly_phone;

Для изменения формы объекта вы просто присваиваете этому указателю адрес объекта производного класса, как показано ниже:

poly_phone = (phone *) home_phone;

Символы (phone *), которые следуют за оператором присваивания, являются оператором приведения типов, который сообщает компилятору C++, что все в порядке, необходимо присвоить адрес переменной одного типа (touch_tone) указателю на переменную другого типа (phone). Поскольку ваша программа может присваивать указателю объекта poly_phone адреса различных объектов, то этот объект может изменять форму, а следовательно, является полиморфным. Следующая программа POLYMORP.CPP использует этот метод для создания объекта-телефона. После запуска программы объект poly_phone меняет форму с дискового телефона на кнопочный, а затем на платный:


#include iostream.h

#include string.h

class phone

{

public:

virtual 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)

{

pay_phone city_phone("702-555-1212", 25);

touch_tone home_phone("555-1212");

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

// Сделать объект дисковым телефоном

phone *poly_phone = rotary;

poly_phone-dial("818-555-1212");

// Заменить форму объекта на кнопочный телефон

poly_phone = (phone *) home_phone;

poly_phone-dial("303-555-1212");

// Заменить форму объекта на платный телефон



poly_phone = (phone *) city_phone;

poly_phone-dial("212-555-1212");

}

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

С:\ POLYMORP ENTER

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

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

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

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

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

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

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


Создание программ с помощью функций


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

Урок 9. Знакомство с функциями.

Урок 10. Изменение значений параметров.

Урок 11. Преимущества использования библиотеки этапа выполнения.

Урок12. Локальные переменные и область видимости.

Урок 13. Перегрузка функций.

Урок 14. Использование ссылок в C++.

Урок 15. Значения параметров по умолчанию.

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



СОЗДАНИЕ ПРОСТОГО КОНСТРУКТОРА


Конструктор представляет собой метод класса, который имеет такое же имя, как и класс. Например, если вы используете класс с именем employee, конструктор также будет иметь имя employee. Подобно этому, для класса с именем dogs конструктор будет иметь имя dogs. Если ваша программа определяет конструктор, C++ будет автоматически вызывать его каждый раз, когда вы создаете объект. Следующая программа CONSTRUC.CPP создает класс с именем employee. Программа также определяет конструктор с именем employee который присваивает начальные значения объекту. Однако конструктор не возвращает никакого значения, несмотря на то, что он не объявляется как void. Вместо этого вы просто не указываете тип возвращаемого значения:

class employee

{

public:

employee(char *, long, float); //Конструктор

void show_employee(void);

int change_salary(float);

long get_id(void);

private:

char name [64];

long employee_id;

float salary;

};

В вашей программе вы просто определяете конструктор так же, как любой другой метод класса:

employee::employee(char *name, long employee_id, float salary)

{

strcpy(employee::name, name) ;

employee::employee_id = employee_id;

if (salary 50000.0)

employee::salary = salary;

else // Недопустимый оклад

employee::salary = 0.0;

}

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

#include iostream.h

#include string.h

class employee

{

public:

employee(char *, long, float);

void show_employee(void);

int change_salary(float) ;


long get_id(void);

private:

char name [64] ;

long employee_id;

float salary;

};

employee::employee(char *name, long employee_id, float salary)

{

strcpy(employee::name, name) ;

employee::employee_id = employee_id;

if (salary 50000.0)

employee::salary = salary;

else // Недопустимый оклад

employee::salary = 0.0;

}

void employee::show_employee(void)

{

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

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

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

}

void main(void)

{

employee worker("Happy Jamsa", 101, 10101.0);

worker.show_employee();

}

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

employee worker("Happy Jamsa", 101, 10101.0);

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

employee worker("Happy Jamsa", 101, 10101.0);

employee secretary("John Doe", 57, 20000.0);

employee manager("Jane Doe", 1022, 30000.0);

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

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

class_name object(valuel, value2, value3)


СОЗДАНИЕ ПРОСТОГО ШАБЛОНА ФУНКЦИИ


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

templateclass Т Т mах(Т а, Т b)

{

if (а b) return(а);

else return(b);

}

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

float max(float, float);

int max(int, int);

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

templateclass Т Т max(Т а, Т b)

{

if (a b) return(а) ;

else return(b);

}

float max(float a, float b)

{

if (a b) return(a) ;

else return(b);

}

Следующая программа МАХ_ТЕМР.СРР использует шаблон тах для создания функции типа int и float.

#include iostream.h

templateclass T Т mах(Т а, Т b)

{

if (a b) return(a);

else return(b);

}

float max(float, float);

int max(int, int);

void main(void)

{

cout "Максимум 100 и 200 равен " max(100, 200) endl;

cout "Максимум 5.4321 и 1.2345 равен " max(5.4321, 1.2345) endl;

}

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

Использование шаблонов функций

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



СОЗДАНИЕ ПРОСТОЙ ПРОГРАММЫ


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

С:\ FIRST ENTER

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

Как известно, при программировании вы можете работать в среде, основанной на командной строке, например MS-DOS или UNIX, или в среде типа Windows. Для упрощения вывода в данной книге подразумевается, что вы работаете из командной строки. В этом случае для выполнения программы FIRST.EXE вы должны ввести имя программы FIRST в ответ на системную подсказку и затем нажать ENTER.

Для начала вам следует использовать текстовый редактор, например EDIT (поставляется с MS-DOS), для создания файла, который содержит операторы программы и называется исходным файлом. Не используйте текстовый процессор, такой как Word или WordPerfect, для создания исходного файла программы. Как известно, текстовые процессоры позволяют вам создавать форматированные документы, которые могут содержать полужирный текст, выровненные поля, а также другие особенности. Чтобы отформатировать документы таким образом, текстовый процессор вставляет специальные (скрытые) символы внутрь документа. Такие символы могут включать или выключать курсив или выбирать определенную ширину полей. Несмотря на то что такие специальные символы имеют смысл для текстового процессора, C++ их не поймет и эти символы приведут к ошибкам.

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

#include iostream.h

void main(void)

{

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


}

Не беспокойтесь, если операторы C++ не имеют для вас смысла. Вы узнаете назначение каждого из них из урока 2. А пока обратите особое внимание на ваш ввод. Удостоверьтесь, например, что вы ввели верное количество кавычек, точек с запятой и скобок. Еще раз более внимательно проверьте операторы своей программы. Если они верны, сохраните операторы в файле FIRST. СРР

Что означает имя?

При создании программы на C++ вы вносите операторы программы в исходный файл. Применяйте расширение СРР, чтобы другие программисты могли понять, что данный файл содержит программу на C++. Далее используйте имя файла, которое указывает назначение программы. Например, если вы создаете финансовую программу, можно использовать имя BUDGET.CPP. Аналогичным образом программу, которая вычисляет оклады в фирме, вы можете назвать SALARY. СРР. Чтобы избежать путаницы, никогда не используйте для названия программы имя существующей команды MS-DOS, например COPY или DEL.


СОЗДАНИЕ ШАБЛОНА КЛАССА


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

class array

{

public:

array(int size);

long sum(void);

int average_value(void);

void show_array(void);

int add_value(int);

private:

int *data;

int size;

int index;

};

Следующая программа I_ARRAY.CPP использует класс array ддя работы со значениями типа int.

#include iostream.h

#include stdlib.h

class array

{

public:

array(int size);

long sum(void);

int average_value(void);

void show_array(void);

int add_value(int) ;

private:

int *data;

int size;

int index;

};

array::array(int size)

{

data = new int [size];

if (data == NULL)

{

cerr "Недостаточно памяти - программа завершается " endl;

exit(l);

}

array:: size = size;

array::index = 0;

}

long array::sum(void)

{

long sum = 0;

for (int i = 0; i index; i++) sum += data[i];

return(sum);

}

int array::average_value(void)

{

long sum = 0;

for (int i = 0; i index; i++) sum += data[i];

return (sum / index);

}

void array::show_array(void)

{

for (int i = 0; i index; i++) cout data[i] ' ';

cout endl;

}

int array::add_value(int value)

{

if (index == size) return(-1); // массив полон


else

{

data[index] = value;

index++;

return(0); // успешно

}

}

void main(void)

{

array numbers (100); // массив из 100 эл-тов

int i;

for (i = 0; i 50; i++) numbers.add_value(i);

numbers.show_array();

cout "Сумма чисел равна " numbers.sum () endl;

cout "Среднее значение равно " numbers.average_value() endl;

}

Как видите, программа распределяет 100 элементов массива, а затем заносит в массив 50 значений с помощью метода add_value. В классе array переменная index отслеживает количество элементов, хранимых в данный момент в массиве. Если пользователь пытается добавить больше элементов, чем может вместить массив, функция add_value возвращает ошибку. Как видите, функция average_value использует переменную index для определения среднего значения массива. Программа запрашивает память для массива, используя оператор new, который подробно рассматривается в уроке 31.

Шаблоны классов

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



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

templateclass T, class T1 class array

{

public:

array(int size);

T1 sum (void);

T average_value(void);

void show_array(void);

int add_value(T);

private:

T *data;

int size;

int index;

};

Этот шаблон определяет символы типов T и T1. В случае массива целочисленных значений Т будет соответствовать int, а T1 — long. Аналогичным образом для массива значений с плавающей точкой значения Т и Т1 равны float. Теперь потратьте время, чтобы убедиться, что вы поняли, как компилятор С++ будет подставлять указанные вами типы вместо символов Т и Т1.

Далее, перед каждой функцией класса вы должны указать такую же запись со словом template. Кроме того, сразу же после имени класса вы должны указать типы класса, например array T, T1::average_value. Следующий оператор иллюстрирует определение функции average_value для этого класса:

templateclass Т, class T1 Т arrayT, T1::average_value(void)

{

T1 sum = 0;

int i;

for (i = 0; i index; i++) sum += data[i] ;

return (sum / index);

}

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

Имя шаблона //---- array int, long numbers (100); ------//Типы шаблона

array float, float values(200);



Программа GENARRAY. CPP использует шаблон класса array для создания двух классов, один из которых работает со значениями типа int, а второй — со значениями типа float.

#include iostream.h

#include stdlib.h

templateclass T, class T1 class array

{

public:

array(int size);

T1 sum(void);

T average_value(void);

void show_array(void);

int add_value(T);

private:

T *data;

int size;

int index;

};

templateclass T, class T1 arrayT, t1::array(int size)

{

data = new T[size];

if (data == NULL)

{

cerr "Недостаточно памяти - программа завершается" endl;

exit(l);

}

array::size = size;

array::index = 0;

}

templateclass T, class T1 Tl arrayT, Tl::sum(void)

{

T1 sum = 0;

for (int i = 0; i index; i++) sum += data[i];

return(sum);

}

templateclass T, class T1 T arrayT, T1::average_value(void)

{

Tl sum =0;

for (int i = 0; i index; i++) sum += data[i];

return (sum / index);

}

templateclass T, class T1 void arrayT, T1::show_array(void)

{

for (int i = 0; i index; i++) cout data[i] ' ';

cout endl;

}

templateclass T, class T1 int arrayT, T1::add_value(T value)

{

if (index == size)

return(-1); // Массив полон

else

{

data[index] = value;

index++;

return(0); // Успешно



}

}

void main(void)

{

// Массив из 100 элементов

arrayint, long numbers(100)7

// Массив из 200 элементов

arrayfloat, float values(200);

int i;

for (i = 0; i 50; i++) numbers.add_value(i);

numbers.show_array();

cout "Сумма чисел равна " numbers.sum () endl;

cout "Среднее значение равно " numbers.average_value() endl;

for (i = 0; i 100; i++) values.add_value(i * 100);

values.show_array();

cout "Сумма чисел равна." values.sum() endl;

cout "Среднее значение равно " values.average_value() endl;

}

Лучшим способом понять шаблоны классов будет напечатать две копии этой программы. В первой копии замените все символы T и Т1 на int и long. A во второй замените Т и Т1 на float.

Объявление объектов, основанных на шаблоне класса

Для создания объектов с использованием шаблона класса вы просто должны указать имя шаблона класса, за которым между левой и правой угловыми скобками укажите типы, которыми компилятор заменит символы Т, T1, T2 и т. д. Затем ваша программа должна указать имя объекта (переменной) со значениями параметров, которые вы хотите передать конструктору класса, как показано ниже:

template_class_nametypel, type2 object_name( parameter1, parameter2);

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

arraychar, int small_numbers(100) ;


СОЗДАНИЕ СОБСТВЕННЫХ ОПЕРАТОРОВ new И delete


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

#include iostream.h

#include stdlib.h

#include string.h

static void operator delete(void *pointer)

{

char *data = (char *) pointer;

int i;

for (i = 0; i 100; i++) data[i] = 0;

cout "Секрет в безопасности!" endl;

free(pointer);

}

void main(void)

{

char *pointer = new char[100];

strcpy(pointer, "Секреты моей компании");

delete pointer;

}

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

char *data = (char *) pointer;

Символы (char *), которые называются оператором приведения типов, предназначены только для того, чтобы сообщить компилятору C++, что функция знает, что она присваивает указатель типа void (см. выше параметры функции) указателю типа char. Если вы опустите оператор приведения типов, программа не откомпилируется. Затем функция копирует нули в 100 байт буфера и освобождает память, используя для этого функцию библиотеки этапа выполнения free. Очень важно отметить, что эта функция (оператор delete) работает только с областью памяти размером 100 байт. Поскольку данная программа выделяет память только один раз, она работает корректно. Если вы измените программу таким образом, чтобы выделялось только десять байт памяти и не сделаете подобных изменений в этой функции, то она перезапишет 90 байт памяти, которые ваша программа, возможно, использовала для других целей, приведя к ошибке. Однако, используя функции библиотеки этапа выполнения, ваши программы могут получить больше информации о размере области памяти, на которую указывает определенный указатель.



Создание вашей первой программы


Все вы использовали компьютерные программы, такие как текстовый процессор, электронные таблицы и даже Microsoft Windows 95. Компьютерные программы, или программное обеспечение, представляют собой файлы, содержащие инструкции, которые указывают компьютеру, что следует делать. Если вы работаете в среде MS-DOS или Windows, то, например, файлы с расширениями ЕХЕ и СОМ содержат команды, которые компьютер может выполнять. Другими словами, файлы содержат специальные инструкции, выполняемые компьютером, обычно одну за другой, для решения определенной задачи. При создании программы вы указываете инструкции, которые компьютер должен выполнить. Из этого урока вы узнаете, как указать такие инструкции с помощью операторов C++. К концу данного урока вы освоите следующие основные концепции:

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

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

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

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

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

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



СОЗДАНИЕ ВТОРОЙ ПРОГРАММЫ


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

#include iostream.h

void main(void)

{

cout "Программировать на C++ просто!";

}

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

С:\ ВСС EASY.CPP ENTER

Если компиляция программы прошла успешно, компилятор создаст выполнимую программу с именем EASY.EXE. Когда вы запустите эту программу, на вашем экране появится следующее сообщение:

С.\ EASY ENTER

Программировать на C++ просто!

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

cout "Программировать на C++ очень просто!";

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

С:\ EASY ENTER

Программировать на C++ очень просто!

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

#include iostream.h

void main(void)

{

cout "Программировать на C++ очень просто!";

cout endl "Можно расслабиться!";

}

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

С:\ EASY ENTER

Программировать на C++ очень просто!

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

C:\ EASY ENTER

Программировать на C++ очень просто!

Можно расслабиться!



СРАВНЕНИЕ ДВУХ ЗНАЧЕНИЙ


Когда ваши программы принимают решение, они обычно выполняют некоторый вид проверки. Например, одна программа может проверять, равны ли тестовые очки студента 100, а вторая программа — составляет ли стоимость покупки больше $50.00. Для выполнения подобных проверок ваши программы будут использовать операции сравнения C++, перечисленные в табл. 7.1. Операции сравнения позволяют проверять, каким образом одно значение соотносится с другим. Другими словами, используя операции сравнения, программы могут проверить, больше одно значение, меньше или равно другому.

Таблица 7.1. Операции сравнения C++.

Операция

Проверка

Пример

==

Если два значения равны

(score == 100)

!=

Если два значения не равны

(old != new)

Если первое значение больше второго

(cost 50.00)

Если первое значение меньше второго

(salary 20000.00)

=

Если первое значение больше или равно второму

(stock_price = 30.0)

=

Если первое значение меньше или равно второму

(age = 21)

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



ССЫЛКА ЯВЛЯЕТСЯ ПСЕВДОНИМОМ


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

int alias_name = variable; //--- Объявление ссылки

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

alias_name = 1001;

variable = 1001;

Следующая программа SHOW_REF.CPP создает ссылку с именем alias_name и присваивает псевдониму переменную number. Далее программа использует как ссылку, так и переменную:

#include iostream.h

void main(void)

{

int number = 501;

int alias_name = number; // Создать ссылку

cout "Переменная number содержит " number endl;

cout "Псевдоним для number содержит " alias_name endl;

alias_name = alias_name + 500;

cout "Переменная number содержит " number endl;

cout "Псевдоним для number содержит " alias_name endl;

}

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

С:\ SHOW_REF ENTER

Переменная number содержит 501

Псевдоним для number содержит 501

Переменная number содержит 1001

Псевдоним для number содержит 1001

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

Объявление ссылки

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

float salary_alias = salary;



СТАРШИНСТВО ОПЕРАЦИЙ


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

result =5+2*3;

В зависимости от порядка, в котором C++ выполняет умножение и сложение, результат будет разным:

result =5+2*3;

=7*3;

= 21;

result =5+2*3;

=5+6;

= 11;

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

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

Таблица 5.3. Старшинство операций в C++.

Операция

Имя

Пример

:: Разрешение области видимости classname::classmember_name

::

Глобальное разрешение

::variable_name

.

Выбор элемента

object.member_name

-

Выбор элемента

pointer-membername

[]

Индексация

pointer[element]

()

Вызов функции

expression(parameters)

()

Построение значения

type(parameters)

sizeof

Размер объекта

sizeof expression

sizeof

Размер типа

sizeof(type)

++

Приращение после

variable++

++

Приращение до

++variable

--

Уменьшение после

variable--

--

Уменьшение до

-- variable

Адрес объекта

variable

*

Разыменование

*pointer

new

Создание (размещение)

new type

delete

Уничтожение (освобождение) delete pointer


delete[]

Уничтожение массива

delete pointer

~

Дополнение

~expression

!

Логическое НЕ

! expression

+

Унарный плюс

+1

-

Унарный минус

-1

()

Приведение

(type) expression

.*

Выбор элемента

object.*pointer

-

Выбор элемента

object-*pointer

*

Умножение

expression * expression

/

Деление

expression / expression

%

Взятие по модулю

expression % expression

+

Сложение (плюс)

expression + expression

-

Вычитание (минус)

expression expression


Статические функции и элементы данных


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

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

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

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

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

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



СТРУКТУРЫ И ФУНКЦИИ


Если функция не изменяет структуру, вы можете передать структуру в функцию по имени. Например, следующая программа SHOW_EMP.CPP использует функцию show_employee для вывода элементов структуры типа employee:

#include iostream.h

#include string.h

struct employee

{

char name[64];

long employee_id;

float salary;

char phone[10];

int office_number;

};

void show_employee(employee worker)

{

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

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

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

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

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

}

void main(void)

{

employee worker;

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

worker.employee_id = 12345;

worker.salary = 25000.00;

worker.office_number = 102;

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

show_employee(worker);

}

Как видите, программа передает переменную типа данной структуры worker в функцию show__employee по имени. Далее функция show_employee выводит элементы структуры. Однако обратите внимание, что программа теперь определяет структуру employee вне main и до функции show_employee. Поскольку функция объявляет переменную worker типа employee, определение структуры employee должно располагаться до функции.



ТРАКТОВКА argv КАК УКАЗАТЕЛЯ


Как вы уже знаете, C++ позволяет вам обращаться к элементам массивов, используя указатели. Следующая программа ARGVPTR.CPP трактует argv как указатель на указатель символьной строки (другими словами, указатель на указатель), чтобы вывести содержимое командной строки:

#include iostream.h

void main(int argc, char **argv)

{

int i = 0;

while (*argv) cout "argv[" i++ "] содержит " *argv++ endl;

}

Выберите время, чтобы проанализировать объявление параметра argvв main:

void main(int argc, char **argv)

Первая звездочка в объявлении сообщает компилятору C++, что argv представляет собой указатель. Вторая звездочка сообщает компилятору, что argv представляет собой указатель на указатель — в данном случае указатель на указатель типа char. Представьте argv как массив указателей. Каждый элемент массива в данном случае указывает на массив типа char.



Указатели


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

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

Когда вы увеличиваете переменную-указатель (переменную, которая хранит адрес), C++ автоматически увеличивает адрес на требуемую величину (на 1 байт для char, на 2 байта для int, на 4 байта для float и т.д.).

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

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



Уменьшение количества операторов


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

while (*string != '\0')

Как уже обсуждалось, символ NULL ('\0') представляет собой значение ASCII 0. Так как C++ использует значение 0, чтобы представить ложь, ваши программы могут записать предыдущий цикл следующим образом:

while (*string)

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

while (*string)

{

cout *string++;

}

while (*string)

{

cout *string;

string++;

}

Оператор cout *string++, заставляет C++ вывести символ, указываемый указателем string, а затем увеличить текущее значение string, чтобы он указывал на следующий символ. С помощью этих методов следующая программа SMARTPTR.CPP иллюстрирует новую реализацию функций show_string и string_length:

#include iostream.h

void show_string(char *string)

{

while (*string) cout *string++;

}

int string_length(char •string)

(

int length = 0;

while (*string++) length++;

return(length) ;

}

void main(void)

{

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

show_string(title) ;

сout " содержит " string_length(title) " символов";

}

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


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

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

while (*string)

{


// операторы

string++;

// продвинуть к следующему символу

}

Следующая функция string_uppercase использует указатели для преобразования символов строки в символы верхнего регистра:

char *string_uppercase(char* string)

{


char *starting_address = string; // адрес string[0];

while (*string)

{


if ((*string = 'а') (*string = 'я')) *string = *string - 'a' + 'A';

string++;

}

return(starting_address);

}

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

cout Btring_uppercase("Привет, мир!") endl;

* Поскольку при переводе книги обрабатываемые символы заменены с английских на русские, то этот алгоритм работает не для всех кодировок кирилицы в DOS и Windows. — Прим. перев.


Управление цифрами значений с плавающей точкой


Если вы используете cout для вывода значения с плавающей точкой, то обычно не можете сделать каких-либо предположений о том, сколько цифр будет выводить cout no умолчанию. Однако, используя манипулятор setprecision, вы можете указать количество требуемых цифр- Следующая программа SETPREC.CPP использует манипулятор setprecision для управления количеством цифр, которые появятся справа от десятичной точки:

#include iostream.h

#include iomanip.h

void main(void)

{

float value = 1.23456;

int i;

for (i = 1; i 6; i++) cout setprecision(i) value endl;

}

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

С:\SETPREC ENTER

/b>

/b>

/b>

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



УПРАВЛЕНИЕ ОТКРЫТИЕМ ФАЙЛА


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

ifstream output_file("FILENAME.EXT", ios::app);

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

Таблица 34. Значения режимов открытия.

Режим открытия

Назначение

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

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

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

ifstream output_file("FIlename.EXT", ios::out | ios::noreplace);



Управление порядком, в котором C++ выполняет операции


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

cost = price_a + price_b * 1.06;

К сожалению, в этом случае C++ сначала выполнит умножение (price_b * 1.06), а затем прибавит значение price_a.

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

result =(2+3)* (3+4);

C++ вычисляет данное выражение в следующем порядке:

result = (2 + 3) * (3 + 4);

= (5) * (3 + 4);

= 5 * (7);

=5*7;

= 35;

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

cost = (price_a + price_b) * 1.06;



УПРАВЛЕНИЕ ШИРИНОЙ ВЫВОДА


Несколько предыдущих программ выводили числа на экран. Чтобы гарантировать правильное отображение этих чисел (с правильной расстановкой пробелов), программы включали пробелы до и после чисел. При выводе на cout или cerr ваши программы могут указать ширину вывода каждого числа, используя модификатор setw (установка ширины). С помощью setw программы указывают минимальное количество символов, занимаемое числом. Например, следующая программа SETW.CPP использует модификатор setw для выбора ширины 3, 4, 5 и 6 для числа 1001. Чтобы использовать модификатор setw, ваша программа должна включать заголовочный файл iomanip.h:

#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;

}

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

С:\ SETW ENTER

Мое любимое число равно1001

Мое любимое число равно1001

Мое любимое число равно 1001

Мое любимое число равно 1001

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

Замечание: Предыдущая программа использует заголовочный файл IOMANIP.H. Вам, возможно, понадобится сейчас напечатать и исследовать содержимое этого файла. Как и в случае с заголовочным файлом IOSTREAM.H вы найдете данный файл внутри подкаталога INCLUDE, который находится в каталоге с файлами вашего компилятора.



Управление свободной памятью


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

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

C++ позволяет вам определить собственный оператор new для выделения и, возможно, инициализации памяти.

C++ позволяет вам определить собственный оператор delete для освобождения памяти.

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



Обычной операцией, которую вы будете


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

count = count + 1;

В данном случае программа сначала выбирает значение count, а затем добавляет к нему единицу. Далее программа записывает результат сложения обратно в переменную count. Следующая программа INTCOUNT.CPP использует оператор присваивания для увеличения переменной count (которая первоначально содержит значение 1000) на единицу (присваивая переменной результат 1001):

#include iostream.h

void main(void)

{

int count = 1000;

cout "начальное значение count равно" count endl;

count = count + 1;

cout "конечное значение count равно" count endl;

}

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

С:\ INCCOUNT ENTER

начальное значение count равно 1000

конечное значение count равно 1001

Так как увеличение значения переменной представляет собой обычную операцию в программах, в C++ есть операция увеличения — двойной знак плюс (++). Операция увеличения обеспечивает быстрый способ прибавления единицы к значению переменной. Следующие операторы, например, увеличивают значение переменной count на 1:

count = count + 1; count++;

Следующая программа INC_OP.CPP использует операцию увеличения для наращивания значения переменной count на 1:

#include iostream.h

void main(void)

{

int count = 1000;

cout "начальное значение count равно " count endl;

count++;

cout "конечное значение count равно " count endl;

}

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


является то, что истина представляется


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

user_owns_a_dog = 0;

Если у пользователя есть собака, вы можете присвоить этой переменной любое ненулевое значение, например 1:

user_owns_a_dog = 1;

Затем ваши программы могут проверить эту переменную, используя оператор if, как показано ниже:

if (user_owns_a_dog)

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

if (user_owns_a_dog == 1)

Следующая программа DOG_CAT.CPP использует переменные user_owns_a_dog и user_owns_a_cat внутри оператора if, чтобы определить, какие животные есть у пользователя.

#include iostream.h

void main(void)

{

int user_owns_a_dog = 1;

int user_owns_a_cat = 0;

if (user_owns_a_dog)

cout "Собаки великолепны" endl;

if (user_owns_a_cat)

cout "Кошки великолепны" endl;

if ((user_owns_a_dog) (user_owns_a_cat))

cout "Собаки и кошки могут ужиться" endl;

if {(user_owns_a_dog) II (user_owns_a_cat))

cout "Домашние животные великолепны!" endl;

}

Экспериментируйте с этой программой, присваивая обоим переменным значение 1 или 0, а затем одной 1, а другой 0 и наоборот. Как видите, проверить два условия очень легко, используя логические операции И и ИЛИ.


ВСТРОЕННЫЕ ФУНКЦИИ


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

#include iostream.b

void show_message(int count, char *message)

{

int i;

for (i = 0; i count; i++) cout '\a';

cout message endl;

}

void main(void)

{

show_message(3, "Учимся программировать на языке C++");

show_mes sage(2, "Урок 35");

}

Следующая программа NO_CALL.CPP не вызывает функцию show_message. Вместо этого она помещает внутри себя те же операторы функции при каждой ссылке на функцию:

#include iostream.h

void main (void)

{

int i;

for (i = 0; i 3; i++) cout '\a';

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

for (i = 0; i 2; i++) cout '\a';

cout "Урок 35" endl;

}

Обе программы выполняют одно и то же. Поскольку программа NO_CALL не вызывает функцию show_message, она выполняется немного быстрее, чем программа CALLBEEP. В данном случае разницу во времени выполнения определить невозможно, но, если в обычной ситуации функция будет вызываться 1000 раз, вы, вероятно, заметите небольшое увеличение производительности. Однако программа NO_CALL более запутана, чем ее двойник CALL_BEEP, следовательно, более тяжела для восприятия.

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



Встроенные функции и ассемблерные коды


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

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

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

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

Для упрощения применения программирования на языке ассемблера C++ позволяет определить функции на встроенном языке ассемблера внутри ваших программ на C++.



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


Как вы уже знаете, при определении класса вы определяете функции этого класса внутри или вне класса. Например, класс employee определяет свои функции внутри самого класса:

class employee

{

public:

employee(char *name, char *position, float salary)

{

strcpy(employee::name, name);

strcpy(employee::position, position);

employee::salary = salary;

}

void show_employee(void)

{

cout "Имя: " name endl;

cout "Должность: " position endl;

cout "Оклад: $" salary endl;

}

private:

char name [64];

char position[64];

float salary;

};

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

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

inline void employee::show_employee(void)

{

cout "Имя: " name endl;

cout "Должность: " position endl;

cout "Оклад: $" salary endl;

}



Второй пример


Если ваша программа передает указатели на параметры, параметры могут быгь любого типа, например int, float или char. Функция, которая использует указатели, объявляет переменные соответствующего типа, предваряя имя каждой переменной звездочкой, подтверждающей, что такая переменная является указателем. Следующая программа SWAPVALS.CPP передает адреса двух параметров типа float в функцию swap_values. Функция в свою очередь использует указатели на каждый параметр, чтобы обменять значения параметров:

#include iostream.h

void swap_values(float *a, float *b)

{

float temp;

temp = *a;

*a = *b;

*b = temp;

}

void main(void)

{

float big = 10000.0;

float small = 0.00001;

swap_values(big, small);

cout "Big содержит " big endl;

cout "Small содержит " small endl;

}

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

void swap_values(float *a, float *b)

Однако функция объявляет переменную temp просто как float, а не как указатель на float. float temp;

Рассмотрим следующий оператор:

temp = *а;

Этот оператор побуждает C++ присвоить переменной temp значение указываемое переменной а (т. е. значение переменной big, равное 10000.0). Поскольку temp имеет тип float, присваивание корректно. Переменная-указатель представляет собой переменную, которая хранит адрес. Следующий оператор объявляет temp как указатель на ячейку памяти, содержащую значение типа float.

float *temp;

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

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

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

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

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


Вы только что узнали, что, используя указатель, ваша функция может сканировать строку символов, пока не будет обнаружен символ NULL. Следующая программа PTR_LEN.CPP использует указатель на строку в функции string_length для определения количества символов в строке:

#include iostream.h

int string_length(char *string)

{

int length = 0;

while (*string != '\0')

{

length++;

string++;

}

return(length);

}

void main(void)

{

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

cout title " содержит " string_length(title) " символов";

}

Как видите, функция string_length сканирует символы строки до тех пор, пока не встретит символ NULL.

Увеличение указателя на символьную строку

Когда программа передает массив в функцию, C++ передает адрес памяти первого элемента этого массива. Используя переменную-указатель, функция может перемещаться по содержимому массива, просто увеличивая значение указателя. Например, предположим, что программа передает в функцию символьную строку "Привет". Внутри функции переменная-указатель сначала указывает на участок памяти, который содержит букву 'П'. Когда функция увеличивает указатель, то он далее указывает на участок памяти, который содержит букву 'р'. По мере увеличения функцией значения указателя, он поочередно указывает на каждую букву в строке и наконец указывает на символ NULL.




При создании ваших собственных типов данных с помощью классов наиболее общей операцией будет проверка, являются ли два объекта одинаковыми. Используя перегрузку, ваши программы могут перегрузить операторы равенства (==), неравенства (!=) или другие операторы сравнения. Следующая программа COMP_STR.CPP добавляет новый оператор в класс string, который проверяет, равны ли два объекта string. Используя перегрузку операторов, ваши программы могут проверять, содержат ли строковые объекты одинаковые строки, как показано ниже:

if (some_string == another_string)

Ниже приведена реализация программы COMP_STR.CPP:

#include iostream.h

#include string.h

class string

{

public:

string(char *); // конструктор

char * operator +(char *);

char * operator -(char);

int operator ==(string);

void show_string(void);

private:

char data[256];

};

string::string(char *str)

{

strcpy(data, str);

}

char * string::operator +(char *str)

{

return(strcat(data, str));

}

char * string::operator -(char letter)

{

char temp[256];

int i, j;

for (i = 0, j = 0; data[i]; i++) if (data[i] 1= letter) temp[j++] = data[i];

temp[j] = NULL;

return(strcpy(data, temp));

}

int string::operator ==(string str)

{

int i;

for (i = 0; data[i] == str.data[i]; i++)

if ((data[i] == NULL) (str.data[i] == NULL)) return(1); // Равно

return (0); //He равно

}

void string::show_string(void)

{

cout data endl;

}

void main(void)

{

string title( "Учимся программировать на C++");

string lesson("Перегрузка операторов");

string str( "Учимся программировать на C++");

if (title == lesson) cout "title и lesson равны" endl;

if (str == lesson) cout "str и lesson равны" endl;

if (title == str) cout "title и str равны" endl;

}

Как видите, перегружая операторы подобным образом, вы упрощаете понимание ваших программ.




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

#include iostream.h

#include string.h

class dogs

{

public:

char breed[64];

int average_weight;

int average_height;

void show_dog(void) ;

};

void dogs::show_breed(void)

{

cout "Порода: " breed endl;

cout "Средний вес: " average_weight endl;

cout "Средняя высота: " average_height endl;

}

void main(void)

{

dogs happy, matt;

strcpy(happy.breed, "Долматин") ;

happy.average_weight = 58;

happy.average_height = 24;

strcpy(matt.breed, "Колли");

matt.average_weight =22;

matt.average_height = 15;

happy.show_breed() ;

matt.show_breed();

}




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

class book

{

public:

book (char *, char *, int);

void show_book(void);

private:

char title[64];

char author[б 4];

int pages;

};

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

char catalog[64];

int checked_out; // 1, если проверена, иначе О

Ваша программа может использовать наследование, чтобы породить класс library _card из класса book, как показано ниже:

class library_card : public book

{

public:

library_card(char *, char *, int, char *, int);

void show_card(void);

private:

char catalog[64] ;

int checked_out;

};

Следующая программа BOOKCARD.CPP порождает класс library_card из клacca book:

#include iostream.h

#include string.h

class book

{

public:

book(char *, char *, int);

void show_book(void);

private:

char title [64];

char author[64];

int pages;

};

book::book(char •title, char *author, int pages)

{

strcpy(book::title, title);

strcpy(book::author, author);

book::pages = pages;

}

void book::show_book(void)

{

cout "Название: " title endl;

cout "Автор: " author endl;

cout "Страниц: " pages endl;

}

class library_card : public book

{

public:

library_card(char *, char *, int, char *, int);

void show_card(void) ;

private:

char catalog[64];

int checked_out;

};

library_card::library_card(char *title, char *author, int pages, char *catalog, int checked_out) : book(title, author, pages)




Следующая программа ALLOCARR.CPP выделяет память для хранения массива из 1000 целочисленных значений. Затем она заносит в массив значения от 1 до 1000, выводя их на экран. Потом программа освобождает эту память и распределяет память для массива из 2000 значений с плавающей точкой, занося в массив значения от 1.0 до 2000.0:

#include iostreain.h

void main(void)

{

int *int_array = new int[1000];

float *float_array;

int i;

if (int_array 1= NULL)

{

for (i = 0; i 1000; i++) int_array[i] = i + 1;

for (i = 0; i 1000; i++) cout int_array[i] ' ';

delete int_array;

}

float_array = new float[2000];

if (float_array != NULL)

{

for (i = 0; i 2000; i++) float_array[i] = (i + 1) • 1.0;

for (i = 0; i 2000; i++) cout float_array[i] ' ' ;

delete float_array;

}

}

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



ВЫПОЛНЕНИЕ ЦИКЛА, ПОКА argv НЕ СОДЕРЖИТ NULL


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

#include iostream.h

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

{

int i;

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

}



ВЫПОЛНЕНИЕ ОПЕРАЦИЙ ЧТЕНИЯ И ЗАПИСИ


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

input_file.read(buffer, sizeof(buffer)) ;

output_file.write(buffer, sizeof(buffer));

Например, следующая программа STRU_OUT.CPP использует функцию write для вывода содержимого структуры в файл EMPLOYEE.DAT:

#include iostream.h

#include fstream.h

void main(void)

{

struct employee

{

char name[64];

int age;

float salary;

} worker = { "Джон Дой", 33, 25000.0 };

ofstream emp_file("EMPLOYEE.DAT") ;

emp_file.write((char *) worker, sizeof(employee));

}

Функция write обычно получает указатель на символьную строку. Символы (char *) представляют собой оператор приведения типов, который информирует компилятор, что вы передаете указатель на другой тип. Подобным образом следующая программа STRU_IN.CPP использует метод read для чтения из файла информации о служащем:

#include iostream.h

#include fstream.h

void main(void)

{

struct employee

{

char name [6 4] ;

int age;

float salary;

} worker = { "Джон Дой", 33, 25000.0 };

ifstream emp_file("EMPLOYEE.DAT");

emp_file.read((char *) worker, sizeof(employee));

cout worker.name endl;

cout worker.age endl;

cout worker.salary endl;

}



ВЫПОЛНЕНИЕ ОПЕРАТОРОВ ПО КРАЙНЕЙ МЕРЕ ОДИН РАЗ


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

do

{

операторы;

}

while (условие_истинно);

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

do ----------------------------------------

{ |

операторы; |

}|

while (условие_истинно); ----------

Если условие ложно, программа не повторяет инструкции цикла, продолжая вместо этого выполнение с первого оператора, следующего за циклом. Обычно цикл do while используется для отображения пунктов меню и затем обработки выбора пользователя. Вам требуется, чтобы программа отобразила меню по крайней мере один раз. Если пользователь выбирает какой-либо пункт меню, кроме Quit, программа выполнит пункт, а затем отобразит меню снова (повторяя оператор цикла). Если пользователь выбирает Quit, цикл завершится и программа продолжит свое выполнение с первого оператора после цикла.

Повторение операторов, если условие истинно

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

do {

оператор;

} while (условие);

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



Выполнение простых операций


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

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

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

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

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

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



ВЫВОД И ВВОД ОДНОГО СИМВОЛА ЗА ОДИН РАЗ


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

#include iostream.h

void main(void)

{

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

int i;

for (i = 0; string[i]; i++) cout.put(string[i]) ;

}

Библиотека этапа выполнения предоставляет функцию с именем toupper, которая возвращает заглавный эквивалент строчной буквы. Следующая программа COUTUPPR.CPP использует функцию toupper для преобразования символа в верхний регистр, а затем выводит эту букву с помощью cout.put.

#include iostream.h

#include ctype.h // прототип toupper

void main(void)

{

char string[] = "C++ language";

int i;

for (i = 0; string[i]; i++) cout.put(toupper(string[i]));

cout endl "Результирующая строка: " string endl;

}

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

С:\ COUTUPPR ENTER

C++ LANGUAGE

Результирующая строка: C++ language

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



ВЫВОД НА СТАНДАРТНОЕ УСТРОЙСТВО ОШИБОК


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

Если вашей программе нужно вывести сообщение об ошибке, вы должны использовать выходной поток cerr. C++ связывает cerr со стандартным устройством ошибок операционной системы. Следующая программа CERR.CPP использует выходной поток cerr для вывода на экран сообщения "Это сообщение появляется всегда ":

#include iostream.h

void main(void)

{

cerr "Это сообщение появляется всегда";

}

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

С:\ CERR FILENAME.EXT ENTER

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



ВЫВОД НЕСКОЛЬКИХ ЗНАЧЕНИЙ ОДНОВРЕМЕННО


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

#include iostream.h

void main(void)

(

cout 1 0 0 1;

}

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

С:\ 1001TOO ENTER

/b>

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

#include iostream.h

void main(void)

{

cout "Мое любимое число равно " 1001;

}

Обратите внимание, что пробел, следующий за словом равно (внутри кавычек), служит для отделения числа 1001 от этого слова. Без пробела число сливается со следующим словом (равно 1001). Подобным образом следующая программа 1001MID.CPP отображает число 1001 в середине символьной строки:

#include iostream.h

void main(void)

{

cout "Число " 1001 " мне очень нравится";

}

Как и ранее, обратите внимание на расстановку пробелов до и после числа 1001.

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

#include iostream.h

void main(void)

{

cout "B " 20 " лет мой оклад был " 493.34 endl;

}

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

С:\ MIXMATCH ENTER

В 20 лет мой оклад был 493.34



Вывод сообщений на экран


Все программы на C++, созданные вами в уроках 1 и 2, использовали выходной поток cout для вывода сообщений на экран. В этом уроке вы будете использовать cout для вывода символов, целых чисел, например 1001, и чисел с плавающей точкой, например 0.12345. К концу данного урока вы освоите следующие основные концепции:

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

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

В C++ можно легко отображать числа в десятичном, восьмеричном (по основанию 8) или шестнадцатеричном (по основанию 16) формате.

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

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

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

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



ВЫВОД В ФАЙЛОВЫЙ ПОТОК


Из урока 33 вы узнали, что cout представляет собой объект типа ostream (выходной поток). Используя класс ostream, ваши программы могут выполнять вывод в cout с использованием оператора вставки или различных методов класса, например cout.put. Заголовочный файл iostream.h определяет выходной поток cout. Аналогично, заголовочный файл fstream.h определяет класс выходного файлового потока с именем ofstream. Используя объекты класса ofstream, ваши программы могут выполнять вывод в файл. Для начала вы должны объявить объект типа ofstream, указав имя требуемого выходного файла как символьную строку, что показано ниже:

ofstream file_object("FILENAME.EXT");

Если вы указываете имя файла при объявлении объекта типа ofstream, C++ создаст новый файл на вашем диске, используя указанное имя, или перезапишет файл с таким же именем, если он уже существует на вашем диске Следующая программа OUT_FILE.CPP создает объект типа ofstream и затем использует оператор вставки для вывода нескольких строк текста в файл BOOKINFO.DAT:

#include fstream.h

void main(void)

{

ofstream book_file("BOOKINFO.DAT");

book_file "Учимся программировать на языке C++, " "Вторая редакция" endl;

book_file "Jamsa Press" endl;

book_file "22.95" endl;

}

В данном случае программа открывает файл BOOKINFO.DAT и затем записывает три строки в файл, используя оператор вставки. Откомпилируйте и запустите эту программу. Если вы работаете в среде MS-DOS, можете использовать команду TYPE для вывода содержимого этого файла на экран:

С:\ TYPE BOOKINFO.DAT ENTER

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

Jamsa Press

$22.95

Как видите, в C++ достаточно просто выполнить операцию вывода в файл.



ВЫВОД ВОСЬМЕРИЧНЫХ И ШЕСТНАДЦАТЕРИЧНЫХ ЗНАЧЕНИЙ


Программы, представленные в этом уроке до сих пор, выводили числа в десятичном виде. В зависимости от назначения ваших программ вам, возможно, потребуется выводить числа в восьмеричном или шестнадцатеричном виде. Для этого можно разместить модификаторы dec, oct и hex внутри выходного потока. Следующая программа ОСТНЕХ.СРР использует эти модификаторы для вывода значений в десятичном, восьмеричном и шестнадцатеричном виде:

#include iostream.h

void main(void)

{

cout "Восьмеричный: " oct 10 ' ' 20 endl;

cout "Шестнадцатеричный: " hex 10 ' ' 20 endl;

cout "Десятичный: " dec 10 ' ' 20 endl;

}

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

С:\ OCTEX ENTER

Восьмеричный: 12 24

Шестнадцатеричный: а 14

Десятичный: 10 20

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



ВЗГЛЯД НА ЦИКЛ while


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

while (условие_верно)

оператор;

Если ваша программа встречает оператор while, она проверяет заданное условие. Если условие истинно, программа выполняет операторы цикла while. После выполнения последнего оператора в цикле, цикл while опять проверяет условие. Если условие все еще истинно, повторяются операторы цикла и повторяется данный процесс. Когда условие, наконец, становится ложным, цикл завершается и программа продолжает свое выполнение с первого оператора, следующего за циклом. Следующая программа GET_YN.CPP просит вас ввести Д для да или Н для нет. Затем программа использует цикл while для чтения символов с клавиатуры, пока пользователь не введет Д или Н. Если пользователь вводит значение, отличное от Д или Н, программа сигналит встроенным динамиком, записывая символ сигнала '\а' в выходной поток cout:

#include iostream.h

void main(void)

{

int done = 0; // Устанавливается в состояние „истина", если введены Д или Н char letter;

while (! done)

{

cout "\nВведите Д или Н" " и нажмите Enter для продолжения: ";

cin letter;

if ((letter == 'Д') II (letter == 'д'))

done = 1;


else if ((letter == 'Н') II (letter == 'н'))

done = 1;

else cout '\а'; // Играть сигнал динамика для неверного символа

}

cout "Вы ввели букву " letter endl;

}

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

Повторение цикла до выполнения заданного условия

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

while (условие)


оператор;

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


ВЗГЛЯД НА ОПЕРАТОРЫ ПРОГРАММЫ


В уроке 1 вы создали на C++ программу FIRST.CPP, которая содержала следующие операторы:

#include iostream.h

void main(void)

{

cout "Учимся программировать на языке С++!";

}

В данном случае программа содержит три оператора. Фигурные скобки (называемые группирующими символами) группируют связанные операторы:

#include iostream.h

void main (void)

{

cout "Учимся программировать "на языке С++!";

}

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



ЗАКРЫТИЕ ФАЙЛА, ЕСЛИ ОН БОЛЬШЕ НЕ НУЖЕН


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

input_file.close ();

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



ЗАМЕНА ВЫРАЖЕНИЙ МАКРОКОМАНДАМИ


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

result = (х*у-3) * (х*у-3) * (х*у-3);

В данном случае программа вычисляет куб выражения (х*у-3). Чтобы улучшить читаемость вашей программы и уменьшить вероятность внесения ошибок из-за опечаток, создайте макрокоманду с именем CUBE, которую ваша программа может использовать следующим образом:

result = CUBE(x*y-3);

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

Для создания макрокоманды вы должны использовать директиву препроцессора #define. Например, следующий оператор создает макрокоманду CUBE:

#define CUBE(x) ((х)*(х)*(х))

Как видите, программа определяет макрокоманду CUBE для умножения параметра х на самого себя дважды. Следующая программа SHOWCUBE.CPP использует макрокоманду CUBE для вывода куба значений от 1 до 10:

#include iostream.h

#define CUBE(x) ((x)* (x)* (x))

void main (void)

{

for (int i = 1; i = 10; i++) cout "Для " i " куб равен " CUBE(i) endl;

}

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

#include iostream.h

#define CUBE(x) ((х)*(х)*(х))

void main(void)

{

for (int i = 1; i = 10; i++) cout "Для " i " куб равен " ((i) * (i) * (i)) endl;

}

Обратите внимание, что предыдущая макрокоманда поместила параметр х внутрь круглых скобок, использовав запись ((х)*(х)*(х)) вместо (х*х*х). При создании макрокоманд вы должны помещать параметры в круглые скобки, как показано выше, тогда можете быть уверены, что C++ трактует ваши выражения именно так, как вы хотите. Как вы помните из урока 5, C++ использует старшинство операций для определения порядка выполнения арифметических операций. Предположим, например, что программа использует макрокоманду CUBE с выражением 3+5-2, как показано ниже:

result = CUBE(3+5-2);

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

result = ((3+5-2) * (3+5-2) * (3+5-2));

Однако, если в определении макрокоманды опустить круглые скобки, препроцессор сгенерирует следующий оператор:

result = (3+5-2*3+5-2*3+5-2);

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



Значения параметров по умолчанию


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

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

• Значения по умолчанию для параметров указываются в заголовке функции при ее определении.

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

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

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



Знакомство с функциями


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

• Функции группируют связанные операторы для выполнения определенной задачи.

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

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

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

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

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



Знакомство с классами C++


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

Для определения класса программа должна указать имя класса, элементы данных класса и функции класса (методы).

Определение класса обеспечивает шаблон, с помощью которого ваши программы могут создать объекты типа этого класса, подобно тому, как программы создают переменные типа int, char и т. д.

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

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



ЗНАКОМСТВО С ОПЕРАТОРОМ if


Оператор C++ if позволяет вашим программам осуществлять проверку и затем на основании этой проверки выполнять операторы. Формат оператора if следующий:

if (условие_выполняется) оператор;

Обычно оператор if выполняет проверку, используя операцию сравнения C++. Если результат проверки является истиной, if выполняет оператор, который следует за ним. Следующая программа FIRST_IF.CPP использует оператор if для сравнения значения переменной test_score со значением 90. Если набранные тестовые очки больше или равны 90, программа выведет сообщение пользователю, что он получил А. В противном случае, если значение меньше 90, программа просто завершается:

#include iostream.h

void main(void)

{

int test_score = 95;

if (test_score = 90) cout "Поздравляем, вы получили А!" endl;

}

Как видите, для выполнения проверки программа использует операцию сравнения C++ "больше или равно" (=). Если результат сравнения значений является истиной, программа выполняет оператор, который следует за if, в данном случае вывод сообщения с использованием cout. Если результат сравнения не является истинным, программа не выводит сообщение. Экспериментируйте с этой программой, изменяя проверочные очки (в том числе и меньше 90), и обратите внимание на работу оператора if.









ios::app
ios::ate Располагает файловый указатель в конце файла.
ios::in Указывает открыть файл для ввода.
ios::nocreate
ios::noreplace Если файл существует, операция открытия должна быть прервана и должна возвратить ошибку.
ios::out Указывает открыть файл для вывода.
ios::trunc Сбрасывает (перезаписывает) содержим, з существующего файла.