Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 [ 9 ] 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

параметр другого типа или этого параметра нет вовсе, но в конце концов ваш код и без этого все равно не был бы переносимым, правда?

• Если функция-член в действительности имеет два или больше параметров (даже если они имеют значения по умолчанию), вы вообще не сможете воспользоваться mem„fun.

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

Увы, на этом наша история не заканчивается. Давайте рассмотрим более обшее следствие такой свободы действий.

Использование указателей на функции-члены - но не со стандартной библиотекой

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

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

Резюме

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

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



Задача 5. Красота обобщенности.

Часть 1: Азы Сложность: 4

Перед тем как приступить к шестой задаче, рассмотрим простой пример гибкого обобщенного кода С++ (примеры кода в этой и следующей задаче взяты из [SutterOOj.

Вопрос для новичка

1. "Шаблоны С++ обеспечивают полиморфизм времени компиляции". Поясните эту фразу.

Вопрос для профессионала

2. Поясните семантик-у приведенной функции. Дайте максимально полный ответ и обязательно поясните, почему в ней использованы два парамсфа шаблона, а не один.

template <с1ass Т1, class Т2> void constructC т1* р, const г2& value ) { new (р) Tl(value);

Решение

1. "Шаблоны С++ обеспечивают полиморфизм времени компиляции". Поясните эту фразу.

Когда мы говорим о полиморфизме в объектно-ориентированном мире, мы подразумеваем полиморфизм времени выполнения, который основан на использовании виртуэльнььх функций. Базовый класс определяет интерфейс, представляющий собой набор виртуальных функций, а производные классы мог)т наследовать их из базового класса и перекрывать их таким образом, чтобы сохранялась предполагаемая интерфейсом семантика. Тогда код, которьп! работает с базовым объектом (получая объект Base через указатель или по ссылке), может точно так же работать и с объектом производного класса.

пример 5~1(а): полиморфизм времени выполнения.

class Base { public:

vi rtual voi d f () ;

virtual void g Q ;

class Derived : public Base {

перекрытие при необходимости f и/или g

void h( Base& b ) { b.fO; b.gO;

int mai n() { Derived d; h( d );

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



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

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

пример 5-1(6): полиморфизм времени компиляции.

class xyzzy { public:

void f ( bool someparm = true ) ; void gO ;

void GoioGazeboO ;

... прочие функции ...

class Murgatroyd { publiс:

void fО;

void g( double two = 6.28, double e = 2.71828 ); i nt HeavensToC const Z& ) const; ... прочие функции ...

tempiate<class T> void h( T& t ) {

t.fO; t.gO;

i nt mai n () { xyzzy x; Murgatroyd m; h( X ); hC m );

До тех пор пока объекты хит будуг иметь типы, обеспечивающие возможность вызова функций f и g без аргументов, функция h будет корректно работать. В примере 5-1(6) в действительности функции f и g имеют разные сигнатуры в разных классах, а кроме того, эти классы, помимо интересующих нас f и д, имеют разные дополнительные функции. Но все это не оказывает никакого влияния на работу функции h. До тех пор пока функции f и g могут быть вызваны без аргументов, компилятор позволит функции h вызывать f и д. Конечно, при вызове эти функции должны делать нечто осмысленное для функции h!

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

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

template <class т1, class т2> void constructC т1* р, const т2& value ) { new (р) Tl(value);

Функция construct со:здаст объект в указанном месте в памяти и инициализирует его данным значением. Оператор new, использованный в данном примере, назьнастся

Задача 5. Красота обобщенности. Часть 1: Азы 43



0 1 2 3 4 5 6 7 8 [ 9 ] 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85