Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Aliens Vs Predator |#10| Human company final
Aliens Vs Predator |#9| Unidentified xenomorph
Aliens Vs Predator |#8| Tequila Rescue
Aliens Vs Predator |#7| Fighting vs Predator

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Страустрап Б. Весь текст 579.17 Kb

Язык С++

Предыдущая страница Следующая страница
1 ... 17 18 19 20 21 22 23  24 25 26 27 28 29 30 ... 50
функции  ()   имеет   более   высокий   приоритет,   чем   операция
разыменования  *,  то  нельзя  писать  просто  *efct("error").  Это
означает *efct("error"),  а это  ошибка в типе. То же относится и к
синтаксису  описаний (см. также #7.3.4).
  Заметьте, что у указателей на функции типы параметров описываются
точно также,  как и  в самих  функциях. В  присваиваниях  указателя
должно  соблюдаться   точное  соответствие  полного  типа  функции.
Например:

  void (*pf)(char*);        // указатель на void(char*)
  void f1(char*);           // void(char*)
  int  f2(char*);           // int(char*)
  void f3(int*);            // void(int*)

  void f()
  {
      pf = &f1;             // ok
      pf = &f2;             // ошибка: не подходит возвращаемый тип
      pf = &f3;             // ошибка: не подходит тип параметра

      (*pf)("asdf");        // ok
      (*pf)(1);             // ошибка: не подходит тип параметра

      int i = (*pf)("qwer"); // ошибка: void присваивается int'у
  }

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

  typedef int (*SIG_TYP)();        // из
  typedef void (*SIG_ARG_TYP);
  SIG_TYP signal(int,SIG_ARG_TYP);

  Бывает часто  полезен вектор  указателей  на  фукнцию.  Например,
система меню  для моего  редактора с  мышью* реализована  с помощью
векторов указателей на функции для представления действий. Подробно
эту систему здесь описать не получится, но вот общая идея:
____________________
  * Мышь  - это  указывающее устройство  по крайней  мере  с  одной
кнопкой. Моя  мышь красная,  круглая и  с  тремя  кнопками.  (прим.
автора)

                             - стр 133 -

  typedef void (*PF)();

  PF edit_ops[] = { // операции редактирования
      cut, paste, snarf, search
  };

  PF file_ops[] = { // управление файлом
      open, reshape, close, write
  };

Затем определяем и инициализируем указатели, определяющие действия,
выбранные в меню, которое связано с кнопками (button) мыши:

  PF* button2 = edit_ops;
  PF* button3 = file_ops;

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

  (button2[3])();

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

                             - стр 134 -

  typedef int (*CFT)(char*,char*);

  int sort(char* base, unsigned n, int sz, CFT cmp)
  /*
      Сортирует "n" элементов вектора "base"
      в возрастающем порядке
      с помощью функции сравнения, указываемой "cmp".
      Размер элементов "sz".

      Очень неэффективный алгоритм: пузырьковая сортировка
  */
  {
      for (int i=0; iname, Puser(q)->name);
  }

  int cmp2(char*p, char* q)        // Сравнивает числа dept
  {
      return Puser(p)->dept-Puser(q)->dept;
  }

  Эта программа сортирует и печатает:

  main ()
  {
      sort((char*)heads,6,sizeof(user),cmp1);
      print_id(heads,6);        // в алфавитном порядке
      cout << "\n";
      sort((char*)heads,6,sizeof(user),cmp2);
      print_id(heads,6);        // по порядку подразделений
  }

  Можно  взять   адрес  inline-функции,   как,  впрочем,   и  адрес
перегруженной функции(#с.8.9).

                             - стр 136 -

     4.7 Макросы

  Макросы* определяются  в #с.11.  В C  они очень  важны, но  в C++
применяются гораздо  меньше. Первое правило относительно них такое:
не используйте  их,  если  вы  не  обязаны  это  делать.  Как  было
замечено, почти каждый макрос проявляет свой изъян или в языке, или
в программе.  Если  вы  хотите  использовать  макросы,  прочитайте,
пожалуйста,  вначале   очень  внимательно   руководство  по   вашей
реализации C препроцессора.
  Простой макрос определяется так:

  #define name rest of line

Когда name встречается как лексема, оно заменяется на rest of line.
Например:

  named = name

после расширения даст:

  named = rest of line

  Можно также определить макрос с параметрами. Например:

  #define mac(a,b) argument1: a argument2: b

При использовании  mac должно  даваться две строки параметра. После
расширения mac() они заменяют a и b. Например:

  expanded = mac(foo bar, yuk yuk)

после расширения даст

  expanded = argument1: foo bar argument2: yuk yuk

  Макросы обрабатывают  строки и о синтаксисе C++ знают очень мало,
а о  типах C++  или областях  видимости -  ничего. Компилятор видит
только  расширенную   форму  макроса,   поэтому  ошибка  в  макросе
диагностируется когда  макрос расширен,  а не когда он определен. В
результате этого возникают непонятные сообщения об ошибках.
  Вот такими макросы могут быть вполне:

  #define Case break;case
  #define nl <<"\n"
  #define forever for(;;)
  #define MIN(a,b) (((a)<(b))?(a):(b))

  Вот совершенно ненужные макросы:

  #define PI 3.141593
  #define BEGIN {
  #define END }

  А вот примеры опасных макросов:
____________________
  * часто называемые также макроопределениями.  (прим. перев.)

                             - стр 137 -

  #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)
и заключайте  вхождения имени параметра макроса в скобки везде, где
это возможно (см. MIN выше).
  Обратите внимание  на различие  результатов расширения  этих двух
макросов:

  #define m1(a) something(a)    // глубокомысленный комментарий
  #define m2(a) something(a)    /* глубокомысленный комментарий */

например,

  int a = m1(1)+2;
  int b = m2(1)+2;

расширяется в

  int a = something(1)    // глубокомысленный комментарий+2;
  int b = something(1)    /* глубокомысленный комментарий */+2;

  С помошью  макросов вы  можете разработать свой собственный язык.
Скорее всего, для всех остальных он будет непостижим. Кроме того, C
препроцессор -  очень простой  макропроцессор. Когда вы попытаетесь
сделать  что-либо  нетривиальное,  вы,  вероятно,  обнаружите,  что
сделать это  либо  невозможно,  либо  чрезвычайно  трудно  (но  см.
#7.3.5).

     4.8 Упражнения

  1. (*1) Напишите следующие описания: функция, получающая параметр
     типа указатель  на символ  и ссылку на целое и не возвращающая
     значения; указатель на такую фунцию; функция, получающая такой
     указатель в  качестве параметра; и функция, возвращающая такой
     указатель.  Напишите  определение  функции,  которая  получает
     такой указатель  как параметр  и возвращает  свой параметр как
     возвращаемое значение. Подсказка: используйте typedef.
  2. (*1) Что это значит? Для чего это может использоваться?

                             - стр 138 -

       typedef int (rifii&) (int, int);

  3. (*1.5)  Напишите   программу  вроде  "Hello,  world",  которая
     получает имя  как параметр командной строки и печатает "Hello,
     имя". Модифицируйте  эту программу  так,  чтобы  она  получала
     получала любое  количество имен  и говорила  hello каждому  из
     них.
  4. (*1.5) Напишите  программу, которая  читает произвольное число
     файлов, имена  которых задаются как аргументы командной стоки,
     и пишет  их один за другим в cout. Поскольку эта программа при
     выдаче конкатенирует  свои параметры, вы можете назвать ее cat
     (кошка).
  5. (*2)  Преобразуйте  небольшую  C  программу  в  C++.  Измените
     заголовочные файлы так, чтобы описывать все вызываемые функции
     и описывать  тип каждого  параметра. Замените,  где  возможно,
     директивы #define  на enum  и const  или inline. Уберите из .c
     файлов описания  extern и  преобразуйте определения  функций к
     синтаксису C++.  Замените вызовы  malloc() и  free() на  new и
     delete. Уберите необязательные приведения типа.
  6. (*2) Реализуйте sort() (#4.6.7) используя эффективный алгоритм
     сортировки.
  7. (*2) Посмотрите на определение struct tnode в с.#8.5. Напишите
     функцию для  введения  новых  слов  в  дерево    узлов  tnode.
     Напишите функцию  для вывода  дерева   узлов  tnode.  Напишите
     функцию для вывода дерева  узлов tnode со словами в алфавитном
     порядке.  Модифицируйте   tnode  так,  чтобы  в  нем  хранился
     (только) указатель  на слово  произвольной длины, помещенное с
     помощью new  в свободную  память.  Модифицируйте  функции  для
     использования нового определения tnode.
  8. (*2)  Напишите "модуль",  реализующий  стек.  Файл  .h  должен
     описывать функции push(), pop() и любые другие удобные функции
     (только). Файл .c определяет функции и данные, необходимые для
     хранения стека.
  9. (*2)  Узнайте,  какие  у  вас  есть  стандартные  заголовочные
     файлы. Составьте  список файлов,  находящихся в /usr/include и
     /usr/include/CC (или там, где хранятся стандртные заголовочные
     файлы  в   вашей  системе).   Прочитайте  все,  что  покажется
     интересным.
  10. (*2) Напишите функцию для обращения двумерного мосссива.
  11. (*2)  Напишите шифрующую  программу, которая  читает из cin и
     пишет в cout закодированные символы. Вы можете воспользоваться
     следующей простой схемой шифровки: Зашифрованная форма символа
     c -  это c^key[i], где key (ключ) - строка, которая передается
     как параметр командной строки. Программа использует символы из
     key   циклически,    пока   не   будет   считан   весь   ввод.
     Перекодирование зашифрованного  текста с  той же  строкой  key
     дает исходный  текст. Если  не передается  никакого ключа (или
     передается  пустая   строка),  то   никакого  кодирования   не
     делается.
  12.  (*3)  Напишите  программу,  которая  поможет  расшифровывать
     тексты, зашифрованные  описанным выше способом, не зная ключа.
     Подсказка: David Kahn: The Code-Breakers, Macmillan, 1967, New
     York, pp 207-213.
  13. (*3)  Напишите  функцию  error,  которая  получает  форматную
     строку в стиле printf, которая содержит директивы %s, %c и %d,
     и произвольное количество параметров. Не используйте printf().

                             - стр 139 -

     Если вы  не знаете  значения %s  и  т.д.,  посмотрите  #8.2.4.
     Используйте .
  14. (*1) Как вы будете выбирать имя для указателя на тип функции,
     определенный с помощью typedef?
  15.  (*2)   Посмотрите  какие-нибудь   программы,  чтобы  создать
     представление о  разнообразии стилей и имен, использующихся на
     практике. Как  используются  буквы  в  верхнем  регистре?  Как
     используется подчерк?  Где используются короткие имена вроде x
Предыдущая страница Следующая страница
1 ... 17 18 19 20 21 22 23  24 25 26 27 28 29 30 ... 50
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 
Комментарии (4)

Реклама