|
Программирование >> Поддержка объектно-ориентированного программирования
*/ { Сортировка вектора base из n элементов в возрастающем порядке; используется функция сравнения, Размер элементов равен sz . Алгоритм очень неэффективный: сортировка пузырьков1м методом на которую указывает cmp. for (int i=0; i<n-1; i++) for (int j=n-1; i<j; j-- ) { char* pj = (char*)base+j*sz; b[j] char* pj1 = pj - sz; if ((*cmp)(pj,pj1) < 0) { поменять местами b[j] for (int k = 0; k<sz; k++ char temp = pj[k]; pj[k] = pj1[k]; pj1[k] = temp; b[j-1] b[j-1] r В подпрограмме sort неизвестен тип сортируемых объектов; известно только их число (размер массива), размер каждого элемента и функция, которая может сравнивать объекты. Мы выбрали для функции sort() такой же заголовок, как у qsort() - стандартной функции сортировки из библиотеки С. Эту функцию используют настоящие программы. Покажем, как с помощью sort() можно отсортировать таблицу с такой структурой: struct user { char* name; имя char* id; пароль int dept; отдел typedef user* Puser; user heads[] = { Ritchie D.M. , dmr , 11271, Sethi R. , ravi , 11272, SZYmanski T.G. , tgs , 11273, Schryer N.L. , nls , 11274, Schryer N.L. , nls , 11275 Kernighan B.W. , bwk , 11276 void print id(Puser v, int n) for (int i=0; i<n; i++) cout << v[i].name << \t << v[i].id << \t << v[i].dept << \n; Чтобы иметь возможность сортировать, нужно вначале определить подходящие функции сравнения. Функция сравнения должна возвращать отрицательное число, если ее первый параметр меньше второго, нуль, если они равны, и положительное число в противном случае: int cmp1(const void* p, const void* q) сравнение строк, содержащих имена return strcmp(Puser(p)->name, Puser(q)->name); int cmp2(const void* p, const void* q) сравнение номеров разделов return Puser(p)->dept - Puser(q)->dept; Следующая программа сортирует и печатает результат: int main() sort(heads,6,sizeof(user), cmp1); print id(heads,6); в алфавитном порядке cout << \n ; sort(heads,6,sizeof(user),cmp2); print id(heads,6); по номерам отделов Допустима операция взятия адреса и для функции-подстановки, и для перегруженной функции ($$R.13.3). Отметим, что неявное преобразование указателя на что-то в указатель типа void* не выполняется для параметра функции, вызываемой через указатель на нее. Поэтому функцию int cmp3(const mytype*, const mytype*); нельзя использовать в качестве параметра для sort(). Поступив иначе, мы нарушаем заданное в описании условие, что cmp3() должна вызываться с параметрами типа mytype*. Если вы специально хотите нарушить это условие, то должны использовать явное преобразование типа. 4.7 Макросредства Макросредства языка определяются в $$R.1 6. В С++ они играют гораздо меньшую роль, чем в С. Можно даже дать такой совет: используйте макроопределения только тогда, когда не можете без них обойтись. Вообще говоря, считается, что практически каждое появление макроимени является свидетельством некоторых недостатков языка, программы или программиста. Макросредства создают определенные трудности для работы служебных системных программ, поскольку они перерабатывают программный текст еще до трансляции. Поэтому, если ваша программа использует макросредства, то сервис, предоставляемый такими программами, как отладчик, профилировщик, программа перекрестных ссылок, будет для нее неполным. Если все-таки вы решите использовать макрокоманды, то вначале тщательно изучите описание препроцессора С++ в вашем справочном руководстве и не старайтесь быть слишком умным. Простое макроопределение имеет вид: #define имя остаток- строки В тексте программы лексема имя заменяется на остаток-строки. Например, объект = имя будет заменено на объект = остаток- строки Макроопределение может иметь параметры. Например: #define mac(a,b) argument1: a argument2: b В макровызове mac должны быть заданы две строки, представляющие параметры. При подстановке они заменят a и b в макроопределении mac(). Поэтому строка expanded = mac(foo bar, yuk yuk) при подстановке преобразуется в expanded = argument1: foo bar argument2: yuk yuk Макроимена нельзя перегружать. Рекурсивные макровызовы ставят перед препроцессором слишком 11 8 сложную задачу: ошибка: #define print(a,b) cout<<(a)<<(b) #define print(a,b,c) cout<<(a)<<(b)<<(c) слишком сложно: #define fac(n) (n>1) ?n*fac(n-1) :1 Препроцессор работает со строками и практически ничего не знает о синтаксисе C++, типах языка и областях видимости. Транслятор имеет дело только с уже раскрытым макроопределением, поэтому ошибка в нем может диагностироваться уже после подстановки, а не при определении макроимени. В результате появляются довольно путанные сообщения об ошибках. Допустимы такие макроопределения: #define Case break;case #define forever for(;;) А вот совершенно излишние макроопределения: #define PI 3.141593 #define BEGIN { #define END } Следующие макроопределения могут привести к ошибкам: #define SQUARE(a) a*a #define INCR xx (xx)++ #define DISP = 4 Чтобы убедиться в этом, достаточно попробовать сделать подстановку в таком примере: int xx = 0; глобальный счетчик void f() { int xx = 0; локальная переменная xx = SQUARE(xx+2); xx = xx +2*xx+2; INCR xx; увеличивается локальная переменная xx if (a-DISP==b) { a-=4==b ... При ссылке на глобальные имена в макроопределении используйте операцию разрешения области видимости ($$2.1 .1 ), и всюду, где это возможно, заключайте имя параметра макроопределения в скобки. Например: #define MIN(a,b) (((a)<(b))?(a):(b)) Если макроопределение достаточно сложное, и требуется комментарий к нему, то разумнее написать комментарий вида /* */, поскольку в реализации С++ может использоваться препроцессор С, который не распознает комментарии вида . Например: #define m2(a) something(a) /* глубокомысленный комментарий */ С помощью макросредств можно создать свой собственный язык, правда, скорее всего, он будет непонятен другим. Кроме того, препроцессор С предоставляет довольно слабые макросредства. Если ваша задача нетривиальна, вы, скорее всего, обнаружите, что решить ее с помощью этих средств либо невозможно, либо чрезвычайно трудно. В качестве альтернативы традиционному использованию макросредств в язык введены конструкции const, inline и шаблоны типов. Например: const int answer = 42; template<class T> inline T min(T a, T b) { return (a<b)?a:b; }
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |