Бьерн Страуструп - Язык программирования С++. Главы 2-4 - Описания

ОГЛАВЛЕНИЕ

2.1  ОПИСАНИЯ

Имя (идентификатор) следует описать прежде, чем оно будет использоваться в программе на  С++. Это означает, что нужно указать его тип, чтобы транслятор знал, к какого вида объектам относится имя. Ниже приведены несколько примеров, иллюстрирующих все разнообразие описаний:
   char ch;
   int count = 1;
   char* name = "Njal";
   struct complex { float re, im; };
   complex cvar;
   extern complex sqrt(complex);
   extern int error_number;
   typedef complex point;
   float real(complex* p) { return p->re; };
   const double pi = 3.1415926535897932385;
   struct user;
   template<class T> abs(T a) { return a<0 ? -a : a; }
   enum beer { Carlsberg, Tuborg, Thor };
Из этих примеров видно, что роль описаний не сводится лишь к привязке типа к имени. Большинство указанных описаний одновременно являются определениями, т.е. они создают объект, на который ссылается имя.

Для ch, count, name и cvar таким объектом является  элемент памяти соответствующего размера. Этот элемент будет использоваться как переменная, и говорят, что для него отведена память. Для real подобным объектом будет заданная функция.

Для константы pi объектом будет число 3.1415926535897932385. Для complex объектом будет новый тип. Для point объектом является тип complex, поэтому point становится синонимом  complex. Следующие описания уже не являются определениями:

   extern complex sqrt(complex);
   extern int error_number;
   struct user;
Это означает, что объекты, введенные ими, должны быть определены где-то в другом месте программы. Тело функции sqrt должно быть указано в каком-то другом описании. Память для переменной error_number типа
 int должна выделяться в результате другого описания error_number. Должно быть и какое-то другое описание типа user,  из которого  можно понять, что это за тип. В программе на языке С++ должно быть только одно определение каждого имени, но описаний может быть много. Однако все описания должны быть согласованы по типу вводимого в них объекта.

Поэтому в приведенном ниже фрагменте содержатся две ошибки:

   int count;
   int count;               // ошибка: переопределение

   extern int error_number;
   extern short error_number; // ошибка: несоответствие типов
Зато в следующем фрагменте нет ни одной ошибки (об использовании extern см. #4.2):
  extern int error_number;
  extern int error_number;
В некоторых описаниях указываются "значения"  объектов, которые они определяют:
  struct complex { float re, im; };
  typedef complex point;
  float real(complex* p) { return  p->re };
  const double pi = 3.1415926535897932385;
Для типов, функций и констант "значение" остается неизменным; для данных, не являющихся константами, начальное значение может впоследствии изменяться:
   int count = 1;
   char* name = "Bjarne";
   //...
   count = 2;
   name = "Marian";
   Из всех определений только следующее не задает значения:
    char ch;
Всякое описание, которое задает значение, является определением.