Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Согласно принципам фон Неймана компьютер должен....docx
Скачиваний:
4
Добавлен:
01.08.2019
Размер:
131.24 Кб
Скачать

Int DoSomething(); void DoSomething();

Если вы попытаетесь откомпилировать программу, содержащую подобные строки, то получите сообщение об ошибке Type mismatch in redeclaration of 'DoSomething()' (Несоответствие типа в повторном объявлении 'DoSomething()'). Эти две функции должны различаться не только возвращаемым значением, чтобы быть перегруженными.

Работа компилятора с перегруженными функциями основана на процессе, называемом искажением имен (name mangling). Это означает, что для внутреннего представления функция получает имя, в котором отражен список ее параметров. После этого ссылка на функцию осуществляется по искаженному имени вместо простого имени, используемого в исходном тексте программы. Например, для функции multiply() с плавающей точкой, искаженное имя будет выглядеть какmultiply$qff.

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

КОГДА НЕОБХОДИМА ПЕРЕГРУЗКА

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

int day_of_week(int julian_day)

{     // Операторы  }

int day_of_week(int month, int day, int year)

{     // Операторы  }

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

Перегрузка функций улучшает удобочитаемость программ

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

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

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

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

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

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

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

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

36. Синтаксис описания шаблона

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

template< typename T >

void sort( T array[], int size ); // прототип: шаблон sort объявлен, но не определён

template< typename T >

void sort( T array[], int size ) // объявление и определение

{

T t;

for (int i = size - 1; i > 0; i--)

for (int j = i; j > 0; j--)

if (array[j] < array[j-1])

{

t = array[j];

array[j] = array[j-1];

array[j-1] = t;

}

}

template< int BufferSize > // целочисленный параметр

char* read()

{

char *Buffer = new char[ BufferSize ];

/* считывание данных */

return Buffer;

}

Ключевое слово typename появилось сравнительно недавно, поэтому стандарт[1] допускает использование class вместо typename:

template< class T >

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

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

Простейшим примером служит определение минимума из двух величин.

Если a меньше b то вернуть а, иначе - вернуть b

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

Так выглядит шаблон функции определения минимума:

template< typename T >

T min( T a, T b )

{

return a < b ? a : b;

}

Для вызова этой функции можно просто использовать её имя:

min( 1, 2 );

min( 'a', 'b' );

min( string( "abc" ), string( "cde" ) );

[править]Вызов шаблонной функции

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

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

sort< int >( i, 5 );

char c[] = "бвгда";

sort< char >( c, strlen( c ) );

sort< int >( c, 5 ); // ошибка: у sort< int > параметр int[] а не char[]

char *ReadString = read< 20 >();

delete [] ReadString;

ReadString = read< 30 >();

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

В примере выше компилятор создал две специализации шаблона функции sort (для типов char и int) и две — шаблона read (для значений BufferSize 20 и 30). Последнее скорее всего расточительно, так как для каждого возможного значения параметра компилятор будет создавать новые и новые экземпляры функций, которые будут отличаться лишь одной константой.