Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
МУ7,8 (2011).doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
207.87 Кб
Скачать

26

Министерство Транспорта Российской Федерации

Федеральное агентство железнодорожного транспорта

Государственное образовательное учреждение высшего профессионального образования

СамарскИЙ государственнЫЙ УНИВЕРСИСТЕТ путей сообщения

Кафедра информационных систем и телекоммуникаций

«Технология программирования»

МЕТОДИЧЕСКИЕ УКАЗАНИЯ

к выполнению лабораторных работ

«Функции», «Перегрузка и шаблоны функций»

для студентов специальности 230201

очной и заочной форм обучения

Составитель: Е.А. Часовских

Самара 2007

УДК 004.422.834 + 004.422.635

Технология программирования: методические указания к выполнению лабораторных работ «Функции» и «Перегрузка и шаблоны функций» для студентов специальности 230201 очной и заочной форм обучения [Текст] / составитель: Е.А. Часовских. – Самара: СамГУПС, 2007. - 26 с.

Утверждены на заседании кафедры 4 октября 2007г., протокол № 2.

Печатается по решению редакционно-издательского совета университета.

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

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

Составитель: Часовских Евгений Анатольевич

Рецензенты: кандидат педагогических наук, доцент кафедры

«Информатика» СамГУПС Буркин В.В.

кандидат технических наук, доцент кафедры «Информационные системы

и технологии» ПГАТИ Овсянников А.С.

Редактор:

Компьютерная верстка:

Подписано в печать Формат 60х90 1/16.

Бумага писчая. Печать оперативная. Усл. п.л.

Тираж экз. Заказ № .

© Самарский государственный университет путей сообщения, 2007

Лабораторная работа №7 функции

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

Краткие сведения из теории

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

Функции нужны для упрощения структуры программы. Разбив задачу на подза­дачи и оформив каждую из них в виде функций, мы поступаем по принципу, изве­стному еще с древних времен: «Разделяй и властвуй». Передача в функцию раз­личных аргументов позволяет, записав ее один раз, использовать многократно для разных данных. Чтобы использовать функцию, не требуется знать, как она работа­ет достаточно знать, как ее вызвать. Точно так же мы включаем телевизор или пользуемся стоп-краном в самолете. Страшно подумать, сколько информации при­шлось бы держать в голове, если бы требовалось в деталях знать устройство всех приборов, которые мы ежедневно применяем! В реальной жизни мы успешно ог­раничиваемся знанием интерфейса, то есть правил обращения (и общения).

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

Формат простейшего заголовка (прототипа) функции:

тип имя ([ список_параметров ]);

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

int main();

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

double sin(double);

Здесь записано, что функция имеет имя sin, вычисляет значение синуса типа double, и для этого нужно передать ей аргумент типа dauble. А вот заголовок функции копирующей блок памяти длиной n байтов, начиная с адреса src, по адресу dest:

void *memcpy(void *dest, const void *src, size_t n);

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

void *memcpy(void *, const void *, size_t);

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

ВНИМАНИЕ: Все, что передается в функцию и обратно, должно отражаться в ее заголовке. Это требова­ние не синтаксиса, а хорошего стиля.

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

int sumdnt а, int b) { // функция находит сумму двух значений return а + b; // тело функции

}

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

Для того чтобы вызвать функцию, надо указать ее имя (тут прослеживается пол­ная аналогия с реальной жизнью, например, «Ихтиандр!» или «Леопольд!»), а так­же передать ей набор аргументов в соответствии с указанным в ее заголовке. Соот­ветствие должно соблюдаться строго, и это естественно: ведь если в заголовке функции указано, сколько величин и какого типа ей требуется для успешной ра­боты, значит, надо их ей передать. Если мясоперерабатывающий конвейер рассчи­тан на то, что на вход поступает корова, а на выходе получается колбаса, трудно рассчитывать на колбасу, подав на вход даже самый современный автомобиль.

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

double у, x1 = 0.34, х2 = 2;

у = sin(x1);

cout << у << ' ' << sin(x2) << endl;

у = sin(x1 + 0.5) - sin(x1 - 0.5);

char *cite = "Never say never";

char b[100];

memcpy(b, cite, strlen(cite) + 1);

int summa, a = 2;

summa = sum(a, 4);

ВНИМАНИЕ: В определении, в объявлении и при вызове одной и той же функции типы и порядок следо­вания параметров должны совпадать. Для имен параметров никакого соответствия не тре­буется.

Многофайловые проекты

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

ПРИМЕЧАНИЕ: Описанные в приложениях интегрированные среды Visual C++ 6.0 и Borland C++З.1, как и подавляющее большинство других, поддерживают создание, компиляцию и сборку много­файловых проектов. С технологией их создания вы можете ознакомиться по приложениям, а здесь мы рассмотрим вопросы, связанные с распределением функций по модулям, разде­лением интерфейса и реализации и особенностями использования глобальных переменных.

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

Исходные тексты совокупности функций для решения какой-либо подзадачи, как правило, размещаются в отдельном модуле (файле). Такой файл называют исход­ным (source file). Обычно он имеет расширение .с или .срр. Прототипы всех функ­ций исходного файла выносят в отдельный так называемый заголовочный файл (header file), для него принято использовать расширение .h или .hpp.

Таким образом, заголовочный файл ххх.h содержит интерфейс для некоторого набора функций, а исходный файл ххх. срр содержит реализацию этого набора. Если некоторая функция из указанного набора вызывается из какого-то другого исход­ного модуля ууу.срр, то вы обязаны включить в этот модуль заголовочный файл ххх.h с помощью директивы #include2. Негласное правило стиля программирования на C++ требует включения этого же заголовочного файла (с помощью #include) и в исходный файл ххх.срр.

Теперь о глобальных переменных. В многофайловом проекте возможны два «вида глобальности». Если некоторая глобальная переменная glvar1 объявлена в файле ххх.срр с модификатором static, то она видима от точки определения до конца этого файла, то есть область ее видимости ограничена файлом. Если же другая гло­бальная переменная glvar2 объявлена в файле ххх.срр без модификатора statiс, то она может быть видимой в пределах всего проекта. Правда, для того, чтобы она оказалась видимой в другом файле, необходимо иметь в этом файле ее объявление с модификатором extern (рекомендуется это объявление помес­тить в файл ххх.h).

В заголовочном файле принято размещать:

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

  • объявления (прототипы) функций;

  • объявления внешних глобальных переменных (с модификатором extern);

  • пространства имен.

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

Каков выход из этой ситуации? Бьерн Страуструп рекомендует использовать так называемые стражи включения, и этот способ нашел широкое применение. Он со­стоит в следующем: чтобы предотвратить повторное включение заголовочных фай­лов, содержимое каждого .h-файла должно находиться между директивами услов­ной компиляции #ifndef и #endif.

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