Опубликован: 25.11.2008 | Уровень: специалист | Доступ: платный | ВУЗ: Нижегородский государственный университет им. Н.И.Лобачевского
Лекция 14:

Функции. Новые возможности в C++

< Лекция 13 || Лекция 14 || Лекция 15 >
Аннотация: Данная лекция посвящена перегрузке функций и шаблонам функций. Приводятся практические примеры использования шаблонов функций, а также основные определения и понятия

13.1. Переопределение (перегрузка) функций

Программисты, работавшие на ранних версиях алгоритмического языка ФОРТРАН, недоумевали, почему в этом языке так много функций. Например:

  • sin(x) – вычисляет синус для вещественного аргумента x ;
  • dsin(dx) – вычисляет синус для вещественного аргумента с удвоенной точностью;
  • csin(cx) – вычисляет синус для комплексного аргумента cx ;
  • cdsin(cdx) – вычисляет синус для комплексного аргумента с удвоенной точностью.

Конечно, для каждой из этих функций в системной библиотеке существует свой алгоритм и своя программа, но разве компилятор не может определить тип аргумента и сам решить, к какой из этих программ следует обратиться. Почему бы не упростить жизнь программисту и не сказать ему – хочешь вычислить синус, так и пользуйся общепринятым в математике обозначением sin(x). А вот в зависимости от типа аргумента тебе сосчитают то, что нужно с соответствующей точностью. Эта идея была реализована в следующих версиях ФОРТРАНА и для пользователя количество математических функций "уменьшилось" почти в 4 раза.

В языке C наблюдается примерно такая же картина, как и в ранних версиях ФОРТРАНА. Представьте себе, что мы часто используем в программе форматный вывод числовых скалярных величин разного типа. Было бы удобно выделить такие операции в отдельные функции. И вот как это могло выглядеть на языке C:

void print_int(char *nx,int x)
{ printf("\n%s=%d",nx,x); }
void print_float(char *nx,float x)
{ printf("\n%s=%f",nx,x); }
void print_double(char *nx,double x)
{ printf("\n%s=%lf",nx,x); }

А в языке C++ эти же процедуры могли выглядеть так:

void print (char *nx,int x)
{ printf("\n%s=%d",nx,x); }
void print (char *nx,float x)
{ printf("\n%s=%f",nx,x); }
void print (char *nx,double x)
{ printf("\n%s=%lf",nx,x); }

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

13.2. Шаблоны функций

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

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

Для написания шаблона функции ее заголовку предшествует следующая конструкция:

template <class Type>

Здесь

  • template – служебное слово (от англ. – шаблон);
  • class – служебное слово (от англ. – класс). На наш взгляд, не самый удачный термин по смыслу. Позднее в C++ появилась более разумная замена: typename – имя типа. Однако версия BC 3.1 с этим термином еще не знакома;
  • Type – уникальный идентификатор, придумываемый программистом для условного обозначения типа обрабатываемых данных.

И в заголовке функции, и в ее теле идентификатором Type можно пользоваться для описания типа параметров и локальных переменных:

template <class Type> void swap(Type &x,Type &y)
{ Type tmp=x; x=y; y=tmp; }

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

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

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

template <class Type1, class Type2, class Type3>...
< Лекция 13 || Лекция 14 || Лекция 15 >
Alexey Ku
Alexey Ku

Попробуйте часть кода до слова main заменить на 

#include "stdafx.h" //1

#include <iostream> //2
#include <conio.h>

using namespace std; //3

Александр Талеев
Александр Талеев

#include <iostream.h>
#include <conio.h>
int main(void)
{
int a,b,max;
cout << "a=5";
cin >> a;
cout <<"b=3";
cin >> b;
if(a>b) max=a;
else max=b;
cout <<" max="<<max;
getch();
return 0;
}

при запуске в visual express выдает ошибки 

Ошибка    1    error C1083: Не удается открыть файл включение: iostream.h: No such file or directory    c:\users\саня\documents\visual studio 2012\projects\проект3\проект3\исходный код.cpp    1    1    Проект3

    2    IntelliSense: не удается открыть источник файл "iostream.h"    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    1    1    Проект3

    3    IntelliSense: идентификатор "cout" не определен    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    6    1    Проект3

    4    IntelliSense: идентификатор "cin" не определен    c:\Users\Саня\Documents\Visual Studio 2012\Projects\Проект3\Проект3\Исходный код.cpp    7    1    Проект3

при создании файла я выбрал пустой проект. Может нужно было выбрать консольное приложение?

 

 

 

Косик Орест
Косик Орест
Россия
Сергей Бородулин
Сергей Бородулин
Россия