Программирование >>  Разработка устойчивых систем 

1 ... 82 83 84 [ 85 ] 86 87 88 ... 196


Существует дополнительная трудность, связанная с различиями в реализации библиотек. Если для функции pow() используется компоновка С (то есть ее имя не украшается , в отличие от функций С++), то этот пример компилироваться не будет. Адаптеру ptr fun необходим указатель на обычную перегружаемую функцию С++.

copy(vd.begln(). vd.endO,

ostrGamJterator<double>(cout, )): cout endl: } III:-

Функция pow() перегружена в стандартном заголовке С++ <cmath> для всех вещественных типов данных:

float pow(float, int): Эффективные версии с целым показателем степени

double pow(double. int):

long double powdong double, int):

float pow(float, float):

double pow(double, double):

long double powdong double, long double):

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

Еще больше трудностей возникает с преобразованием функции класса в объект функции, подходящий для работы с обобщенными алгоритмами. Рассмотрим простой пример: имеется классическая иерархия геометрических фигур. Требуется вызвать функцию draw() для каждого указателя на Shape, хранящегося в контейнере:

; C06:MemFunl.cpp

Вызов функций класса по указателям

linclude <algor1thm>

linclude <functional>

linclude <iostream>

linclude <vGCtor>

linclude ../purge.h

using namespace std:

class Shape { public:

virtual void drawO = 0:

virtual -ShapeO {}

class Circle : public Shape { public:

virtual void drawO { cout Circle::Draw() endl: } -CircleO { cout Circle: :~Circle() endl: }

class Square : public Shape { public:

virtual void drawO { cout Square:: DrawO endl: } -Squared { cout Square::-Square() endl: }

int mainO { vector<Shape*> vs: vs.push back(new Circle):



vs.push back(new Square);

for each(vs.begin(), vs.endО. mem fun(&Shape::draw)); purge(vs); } III:-

Алгоритм for each() передает каждый элемент интервала объекту функции, определяемому третьим аргументом. Здесь нам нужно, чтобы объект функции представлял одну из функций класса, поэтому аргумент объекта функции становится указателем на объект для вызова функции. Для получения такого объекта используется шаблон mem fun(), в аргументе которого передается указатель на функцию luiacca.

Функция mem fun() создает объекты функций; их вызов производится через указатель на объект, функция которого вызывается, тогда как при использовании mem fun ref() функция вызывается непосредственно для объекта. Один набор перегруженных версий mem fun() и mem fun ref() предназначен для функций с нулем и с одним аргументом, причем их количество увеличивается вдвое для константных и неконстантных функций класса. Тем не менее, шаблоны и перегрузка избавляют вас от всех сложностей выбора нужной версии - вам остается лишь запомнить, в каких случаях используется mem fun(), а в каких - mem fun ref().

Допустим, имеется контейнер объектов (не указателей!), и вы хотите вызвать функцию класса с аргументом, при этом передаваемый аргумент берется из другого контейнера. Для решения этой задачи используется вторая перегруженная форма алгоритма transform():

: C06;MemFun2.cpp

Вызов функций класса по ссылке на объект

linclude <algorithm>

linclude <functional>

linclude <iostream>

linclude <iterator>

linclude <vector>

using namespace std;

class Angle { int degrees; public;

AngleCint deg) ; degrees(deg) {}

int muKint times) { return degrees *= times: }

int mainO { vGctor<Angle> va; forCint i = 0; i < 50; i += 10)

va.push back(Angle(i)); int x[] = { 1. 2. 3. 4. 5 }; transformCva.beginO. va.endO. x,

ostream iterator<int>(cout, ).

mem fun ref(&Angle:;mul)); cout endl;

Результат: 0 20 60 120 200 } III:-

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



Если компилятор определяет string::empty с архументами по умолчанию (что разрешено), то выражение &string::empty определяет указатель на функцию класса с максимальным числом аргументов. Поскольку компилятор не сможет предоставить дополнительные значения по умолчанию, при попытке применить string::empty через mem fun ref компилятор выдаст сообщение об отсутствии аргументов.

мый для каждого элемента в первом интервале. Объект функции создается из адаптера mem fun ref() и указателя на функцию. Учтите, что для шаблонов transforni() и for each() установлены некоторые ограничения; transform() требует, чтобы вызываемая функция возвращала значение, а у for each() не существует версии с передачей двух аргументов вызываемой функции. Следовательно, при использовании шаблона transform() или for each() вам не удастся вызвать функцию класса, которая возвращает void и получает дополнительный аргумент.

Адаптер mem fun ref() может использоваться с функциями классов стандартной библиотеки, если ваш компилятор не добавляет аргументы по умолчанию помимо обычных аргументов, указанных в стандарте. Предположим, требуется найти в читаемом файле пустые строки. Возможно, ваш компилятор позволит задействовать функцию string::empty() так, как показано в следующем примере:

: C06:FindBlanks.cpp

Использование mem fun ref() с string::emptyО

#include <algorithm>

#i nclude <cassert>

#i nclude <cstddef>

#include <fstream>

#include <functional>

#include <string>

linclude <vector>

linclude ../require.h

using namespace std:

typedef vector<string>::iterator LSI:

int mainCint argc. char* argv[]) { char* fname = FindBlanks.cpp : if(argc > 1) fname = argv[l]: ifstream in(fname): assure(in. fname): vector<string> vs: string s;

while(getline(in. s))

vs.push back(s): vector<string> cpy = vs: Для тестирования LSI Isi = find if(vs.begin(). vs.endO,

mem fun ref(&str1ng::empty)): whiledsi != vs.endO) { *lsi = A BLANK LINE : Isi = find if(vs.begin(). vs.endO. mem fun ref(&string::empty));

for(size t i = 0: i < cpy.sizeO: i++) if(cpy[i].SizeO == 0)

assert(vs[i] == A BLANK LINE ): else

assert(vs[i] != A BLANK LINE ): } /:-



1 ... 82 83 84 [ 85 ] 86 87 88 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика