Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кетков.doc
Скачиваний:
17
Добавлен:
27.09.2019
Размер:
2.22 Mб
Скачать

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

Встраиваемые (inline) функции – это очень короткие функции, реализуемые небольшим числом машинных команд. К ним невыгодно обращаться с использованием стандартного механизма, требующего обязательной засылки передаваемых аргументов в стек, извлечения данных из стека, засылки возвращаемого результата в стандартный регистр и т.п. Гораздо проще на место вызова inline-функции вставить и настроить само тело функции. Это намного эффективнее, особенно в тех случаях, когда работа функции сводится к нескольким машинным командам. Такая техника компиляции напоминает процедуру макроподстановки в ассемблере или процесс обработки препроцессором директив #define.

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

inline int even(int x)

{ return !(x%2); }

inline double min(double a,double b)

{ return a < b ? a : b; }

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

class sample {

int i,j; //приватные данные

public

sample(int x,int y):i(x),j(y){} //встраиваемый конструктор

int is_divisor(); //описание функции вынесено

};

inline int sample::is_divisor() //вынесенная встроенная функция

{ return !(i%j); }

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

#define Cube(x) (x)*(x)*(x)

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

q=4;

cout << Cube(q++);

Макроподстановка заменит вторую строку на:

cout << (q++)*(q++)*(q++);

В соответствии с правилами выполнения инкрементных операций такое произведение в результате даст 5*6*7. Какой же это куб?

Если же оформить эту процедуру как встроенную функцию, то никакие выкрутасы в смысле языка C на правильность результата не повлияют:

inline int Cube(int x) { return x*x*x; }

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

inline template <class T> T Cube(T x) { return x*x*x; }

Результат использования такого шаблона приведен ниже:

#include <iostream.h>

#include <conio.h>

inline template <class T> T Cube(T x) { return x*x*x; }

void main()

{ int x=2;

float y=3;

double z=4;

cout<<Cube(x)<<endl;

cout<<Cube(y)<<endl;

cout<<Cube(z)<<endl;

getch();

}

//=== Результат работы ===

8

27

64