Главная · Поиск книг · Поступления книг · 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 ... 15 16 17 18 19 20 21  22 23 24 25 26 27 28 ... 50
необходимо знать пользователю, остальные скрыты. Это качество часто
называют скрытием  данных, хотя данные - лишь часть того, что может
быть скрыто.  Модули такого  вида  обеспечивают  большую  гибкость.
Например, реализация  может состоять из одного или более .c файлов,
и в  виде .h файлов может быть предоставлено несколько интерфейсов.
Информация, которую  пользователю  знать  не  обязательно,  искусно
скрыта в  .c файлах.  Если важно,  что пользователь не должен точно
знать, что  содержится в  .c файлах, не надо делать их доступными в
исходом  виде.   Достаточно  эквивалентных   им   выходных   файлов
компилятора (.o файлов).
  Иногда  возникает   сложность,  состоящая  в  том,  что  подобная
гибкость  достигается   без  формальной   структуры.  Сам  язык  не
распознает такой модуль как объект, и у компилятора нет возможности
отличить .h  файлы, определяющие имена, которые должны использовать
другие модули  (экспортируемые), от  .h файлов,  которые  описывают
имена из других модулей (импортируемые).
  В  других  случаях  может  возникнуть  та  проблема,  что  модуль
определяет множество  объектов, а  не новый  тип. Например,  модуль
table определяет одну таблицу, и если вам нужно две таблицы, то нет
простого способа  задать вторую  таблицу с  помощью понятия модуля.
Решение этой проблемы приводится в Главе 5.
  Каждый    статически     размещенный    объект    по    умолчанию
инициализируется   нулем,    программист   может    задать   другие
(константные)  значения.   Это   только   самый   примитивный   вид
инициализации. К  счастью, с  помощью  классов  можно  задать  код,
который выполняется  для инициализации перед тем, как модуль каким-
либо образом  используется,  и/или  код,  который  запускается  для
очистки после последнего использования модуля; см. #5.5.2.

                             - стр 121 -

     4.5 Как Создать Библиотеку

  Фразы  типа   "помещен  в   библиотеку"  и   "ищется  в  какой-то
библиотеке" используются часто (и в этой книге, и в других), но что
это означает для C++ программы? К сожалению, ответ зависит от того,
какая   операционная   система   используется;   в   этом   разделе
объясняется, как  создать библиотеку  в 8-ой  версии системы  UNIX.
Другие системы предоставляют аналогичные возможности.
  Библиотека  в   своей  основе   является  множеством  .o  файлов,
полученных в  результате компиляции  соответствующего множества  .c
файлов.  Обычно  имеется  один  или  более  .h  файлов,  в  которых
содержатся описания  для использования  этих .o  файлов. В качестве
примера рассмотрим случай, когда нам надо задать (обычным способом)
набор  математических   функций  для   некоторого   неопределенного
множества  пользователей.   Заголовочный  файл   мог  бы  выглядеть
примерно так:

  extern double sqrt(double);        // подмножество
  extern double sin(double);
  extern double cos(double);
  extern double exp(double);
  extern double log(double);

а определения  этих функций  хранились бы, соответственно, в файлах
sqrt.c, sin.c, cos.c, exp.c и log.c.
  Библиотеку с именем math.h можно создать, например, так:

  $ CC -c sqrt.c sin.c cos.c exp.c log.c
  $ ar cr math.a sqrt.o sin.o cos.o exp.o log.o
  $ ranlib math.a

  Вначале исходные файлы компилируются в эквивалентные им объектные
файлы. Затем  используется команда ar, чтобы создать архив с именем
math.a. И, наконец, этот архив индексируется для ускорения доступа.
Если в  вашей системе нет команды runlib, значит она вам, вероятно,
не  понадобится.   Подробности  посмотрите,   пожалуйста,  в  вашем
руководстве в  разделе под  заголовком ar.  Использовать библиотеку
можно, например, так:

  $ CC myprog.c math.a

  Теперь разберемся,  в чем  же преимущества  использования  math.a
перед просто непосредственным использованием .o файлов? Например:

  $ CC myprog.c sqrt.o sin.o cos.o exp.o log.o

  Для большинства  программ определить  правильный набор .o файлов,
несомненно, непросто.  В приведенном  выше примере  они  включались
все, но  если функции  в myprog.c  вызывают только функции sqrt() и
cos(), то кажется, что будет достаточно

  $ CC myprog.c sqrt.o cos.o

Но это не так, поскольку cos.c использует sin.c.
  Компоновщик, вызываемый  командой CC  для обработки  .a файла  (в
данном случае, файла math.a) знает, как  из того множества, которое

                             - стр 122 -

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

     4.6 Функции

  Обычный способ  сделать что-либо  в C++  программе -  это вызвать
функцию, которая  это делает. Определение функции является способом
задать то, как должно делаться некоторое действие. Фукнция не может
быть вызвана, пока она не описана.

     4.6.1 Описания Функций

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

  extern double sqrt(double);
  extern elem* next_elem();
  extern char* strcpy(char* to, const char* from);
  extern void exit(int);

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

  double sr2 = sqrt(2);

будет  правильно   обращаться  к  функции  sqrt()  со  значением  с
плавающей точкой 2.0. Значение такой проверки типа и преобразования
типа огромно.
  Описание функции  может содержать  имена  параметров.  Это  может
помочь читателю, но компилятор эти имена просто игнорирует.

     4.6.2 Определения Функций

  Каждая  функция,  вызываемая  в  программе,  должна  быть  где-то
определена (только  один раз).  Определение функции  - это описание
функции, в котором приводится тело функции. Например:

  extern void swap(int*, int*);    // описание

  void swap(int*, int*)            // определение
  {
      int t = *p;
      *p =*q;
      *q = t;
  }

                             - стр 123 -

  Чтобы избежать  расходов на  вызов функции, функцию можно описать
как inline  (#1.12), а  чтобы обеспечить  более  быстрый  доступ  к
параметрам, их  можно описать  как register (#2.3.11). Оба средства
могут использоваться  неправильно, и  их следует избегать везде где
есть какие-либо сомнения в их полезности.

     4.6.3 Передача Параметров

  Когда вызывается  функция, дополнительно выделяется память под ее
формальные параметры, и каждый формальный параметр инициализируется
соответствующим  ему  фактическим  параметром.  Семантика  передачи
параметров идентична  семантике  инициализации.  В  частности,  тип
фактического   параметра   сопоставляется   с   типом   формального
параметра,  и   выполняются   все   стандартные   и   определеннные
пользователем  преобразования   типов.  Есть   особые  правила  для
передачи  векторов   (#4.6.5),  средство  передавать  параметр  без
проверки (#4.6.8)  и средство  для задания  параметров по умолчанию
(#4.6.6). Рассмотрим

  void f(int val, int& ref)
  {
      val++;
      ref++;
  }

Когда вызывается  f(), val++  увеличивает локальную  копию  первого
фактического  параметра,   тогда  как   ref++  увеличивает   второй
фактический параметр. Например:

  int i = 1;
  int j = 1;
  f(i,j);

увеличивает j, но не i. Первый параметр, i, передается по значению,
второй параметр,  j, передается  по ссылке.  Как уже  отмечалось  в
#2.3.10, использование  функций,  которые  изменяют  переданные  по
ссылке параметры,  могут сделать  программу трудно  читаемой, и  их
следует избегать  (но см.  #6.5 и  #8.4). Однако  передача большого
объекта по  ссылке может быть гораздо эффективнее, чем передача его
по значению.  В этом случае параметр можно описать как const, чтобы
указать, что  ссылка применяется  по соображениям  эффективности, а
также чтобы  не  позволить  вызываемой  функции  изменять  значение
объекта:

  void f(const large& arg)
  {
      // значение "arg" не может быть изменено
  }

  Аналогично,  описание  параметра  указателя  как  const  сообщает
читателю, что  значение объекта,  указываемого указателем, функцией
не изменяется. Например:

                             - стр 124 -

  extern int strlen(const char*);        // из
  extern char* strcpy(char* to, const char* from);
  extern int strcmp(const char*, const char*);

Важность такой практики растет с размером программы.
  Заметьте, что  семантика передачи параметров отлична от семантики
присваивания. Это  важно для const параметров, ссылочных параметров
и параметров некоторых типов, определяемых пользователем (#6.6).

     4.6.4 Возврат Значения

  Из функции,  которая  не  описана  как  void,  можно  (и  должно)
возвращать  значение.  Возвращаемое  значение  задается  опреатором
return. Например:

  int fac(int n) {return (n>1) ? n*fac(n-1) : 1; }

В функции может быть больше одного оператора return:

  int fac(int n)
  {
      if (n > 1)
          return n*fac(n-1);
      else
          return 1;
  }

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

  double f()
  {
      // ...
      return 1;    // неявно преобразуется к double(1)
  }

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

  int* f() {
      int local = 1;
      // ...
      return &local;            // так не делайте
  }

Эта ошибка менее обычна, чем эквивалентная ошибка при использовании
ссылок:

                             - стр 125 -

  int& f() {
      int local = 1;
      // ...
      return local;            // так не делайте
  }

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

  int& f() { return 1;}        // так не делайте

     4.6.5 Векторные Параметры

  Если  в   качестве  параметра  функции  используется  вектор,  то
передается указатель на его первый элемент. Например:

  int strlen(const char*);

  void f()
  {
      char v[] = "a vector"
      strlen(v);
      strlen("Nicholas");
  };

  Иначе  говоря,  при  передаче  как  параметр  параметр  типа  T[]
преобразуется к T*. Следовательно, присваивание элементу векторного
параметра изменяет  значение  элемента  вектора,  который  является
параметром. Другими  словами, вектор  отличается от  всех остальных
типов тем,  что вектор  не передается  (и не может передаваться) по
значению.
  Размер вектора  недоступен вызываемой  функции.  Это  может  быть
неудобно, но  эту сложность  можно  обойти  несколькими  способами.
Строки оканчиваются нулем, поэтому их размер можно легко вычислить.
Для других  векторов  можно  передавать  второй  параметр,  который
задает размер, или определить тип, содержащий указатель и индикатор
длины, и  передавать его  вместо просто  вектора (см. также #1.11).
Например:

  void compute1(int* vec_ptr, int vec_size);    // один способ

  struct vec {                                  // другой способ
      int* ptr;
      int size;
Предыдущая страница Следующая страница
1 ... 15 16 17 18 19 20 21  22 23 24 25 26 27 28 ... 50
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 
Комментарии (4)

Реклама