Встраиваемые (inline) функции. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Встраиваемые (inline) функции.



 

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

inline int sum(int a, int b) { return (a + b);}  // определение inline – функции

 

Перегруженные функции

 

В программировании то и дело случается писать функции для схожих действий, выполняемых над различными типами и наборами данных. Возьмите, например, функцию, которая должна возвращать квадрат своего аргумента. В C/C++ возведение в квадрат целого и числа с плавающей точкой – существенно разные операции. Вообще говоря, придется написать две функции – одну, принимающую целый аргумент и возвращающую целое, и вторую, принимающую тип double и возвращающую также double. В С функции должны иметь уникальные имена. Таким образом, перед программистом встает задача придумывать массу имен для различных функций, выполняющих аналогичные действия. Например, SquareInt() и SquareDbl().

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

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

 

int Square(int arg)

{

return arg*arg;

}

double Square(double arg)

{

return arg*arg;

}

char *Square(const char *arg, int n)

{

static char res[256];

int j = 0;

while (*arg && j < n)

{ if (*arg!= ' ') res[j++] = *arg;

res[j++] = *arg++;}

res[j] = 0;

return res;

}

int main(void)

{

int x = 11;

double у = 3.1416;

char msg[] = "Output from overloaded Function!";

printf("Output: %d, %f, %s\n", Square (x), Square (y), Square (msg, 32));

}

Результат работы программы показан на рис. 6.1.

 

Рис. 6.1Пример с тремя перегруженными функциями

 

При вызове перегруженной функции компилятор определяет, какую именно функцию требуется вызвать, по типу фактических параметров. Этот процесс называется разрешением перегрузки (перевод английского слова resolution в смысле «уточнение»). Тип возвращаемого функцией значения в разрешении не участвует. Механизм разрешения сводится к тому, чтобы использовать функцию с наиболее подходящими аргументами и выдать сообщение, если такой не найдется. Допустим, имеется четыре варианта функции, определяющей наибольшее значение:

// Возвращает наибольшее из двух целых:

int max(int, int):

// Возвращает подстроку наибольшей длины:

char* max(char*, char*);

// Возвращает наибольшее из первого параметра и длины второго:

int max (int, char*):

// Возвращает наибольшее из второго параметра и длины первого:

int max (char*, int);

void f(int a, int b, char* c, char* d)

{

cout << max (a, b) << max(c, d) << max(a, c) << max(c, b);

}

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

Если точного соответствия не найдено, выполняются продвижения порядковых типов в соответствии с общими правилами преобразования типов, например, bool и char в int, float в double и т. п. Далее выполняются стандартные преобразования типов, например, int в double или указателей в void*. Следующим шагом является выполнение преобразований типа, заданных пользователем, а также поиск соответствий за счет переменного числа аргументов функций. Если соответствие на одном и том же этапе может быть получено более чем одним способом, вызов считается неоднозначным и выдается сообщение об ошибке.

Неоднозначность может появиться при:

- преобразовании типа;

- использовании параметров-ссылок;

- использовании аргументов по умолчанию.

Пример неоднозначности при преобразовании типа:

 

float f(float i)

{

cout << "function float f(float i)" << endl;

return i;

}

double f(double i)

{

cout << "function double f(double i)" << endl;

return i*2;

}

int main()

{

float x = 10.09:

double у = 10.09;

cout << f(x) << endl; // Вызывается f(float)

cout << f(y) << endl; // Вызывается f(double)

cout << f(10) << endl; // Неоднозначность - как преобразовать 10: во float или double?

}

 

Для устранения этой неоднозначности требуется явное приведение типа для константы 10.

Пример неоднозначности при использовании параметров-ссылок: если одна из перегружаемых функций объявлена как int f(int a, int b), а другая – как int f (int a, int &b), то компилятор не сможет узнать, какая из этих функций вызывается, так как нет синтаксических различий между вызовом функции, которая получает параметр по значению, и вызовом функции, которая получает параметр по ссылке.

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

 

int f(int a){return a;}

int f(int a, int b = l){return a * b;}

int main()

{

cout << f(10, 2);  // Вызывается вторая функция f(int, int)

cout << f(10); // Неоднозначность - что вызывается: f(int, int) или f(int)?

}

Ниже приведены правила описания перегруженных функций.

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

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

Функции не могут быть перегружены, если описание их параметров отличается только модификаторами const, volatile или использованием ссылки (например, int и const int или int и int&).

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

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

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

void Func(void); // @Func$qv

void Func(int); // @Func$qi

void Func(int, int); // @Func$qii

void Func(*char); // @Func$qpc

void Func(unsigned); // @Func$qui

void Func(const char*); // @Func$qpxc

Тип возвращаемого значения никак не отражается на декорировании имени.

 

Спецификация связи

 

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

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

Вот примеры:

// Функция, которую можно вызывать из С (прототип):

extern "С" void FuncForC(void);

// Прототип функции из некоторой библиотеки не на C++:

extern "С" void SomeExtFunc (int);

Следует отличать спецификацию связи от соглашений o вызове. Функция, например, может вызываться в соответствии с соглашением Pascal (что означает определенный порядок передачи параметров и имя в верхнем регистре), но иметь спецификацию связи C++, т. е. декорированное имя. Алгоритм здесь такой: сначала формируется (если не указано extern "С") декорированное имя, а затем оно подвергается модификации в соответствии с соглашением о вызове.

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

extern "С"

{

#include "asmlib.h"

#include "someclib.h"

}

 

Задание к лабораторной работе №8

 

Задание 1

Даны две квадратные матрицы n´n. Напечатать ту из них, которая имеет минимальный “след” (т.е. сумму элементов главной диагонали). При решении создать функцию для нахождения следа матрицы и функцию печати матрицы.

 

Задание 2

Написать и протестировать функцию compress (), которая сжимает массив, удаляя из него элементы равные числу, введенному с клавиатуры.

 

Задание 3

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

 

Задание 4

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

 

Задание 5

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

 

Задание 6

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

 

Задание 7

Найти натуральное число из интервала [n1, n2] с максимальной суммой делителей. Для нахождения суммы делителей написать функцию.

 

Задание 8

Написать и протестировать функцию, которая все нулевые элементы заданного массива переносит в его конец, а остальные – в начало, сохраняя порядок их следования. Размерность массива определяется по количеству введенных элементов.

 

 

Задание 9

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

 

Задание 10

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

 

Задание 11

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

Задание 12

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

 

Задание 13

Написать и протестировать функцию shift _ r (mas, n, k), которая циклически сдвигает массив mas длины n вправо на k позиций.

 

Задание 14

Написать и протестировать функцию, которая возвращает наименьшее среди элементов массива X(n), которые не являются элементами массива Y(m).

 

Задание 15

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

 

Содержание отчета

 

Отчет выполняется в редакторе Word 2000 и должен содержать:

 

1. Листинг программ на языке Си, решающих задачи в соответствии с вариантом (номером компьютера) задания;

2. Блок-схему алгоритма программ;

3. Пояснения по методу решения задач;

4. Результаты тестирования программ.

 

При оформлении отчета следует пользоваться копированием листинга и результата тестирования в Word. Последний копируется с помощью комбинации клавиш ALT Prt Sc при условии активности консольного окна, что означает копирование графики окна в буфер обмена Windows. Затем окно вставляется в документ Word как любой другой объект.

 


 

ЛАБОРАТОРНАЯ РАБОТА №9

 

Строки

 



Поделиться:


Последнее изменение этой страницы: 2021-11-27; просмотров: 129; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.138.110.119 (0.044 с.)