Читать интересную книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 82 83 84 85 86 87 88 89 90 ... 337
z является локальной

}

int g(int x)   // переменная g является глобальной;

               // переменная x является локальной в функции g

{

  int f = x+2; // переменная f является локальной

  return 2*f;

}

Изобразим это графически.

Здесь переменная x, объявленная в функции f(), отличается от переменной x, объявленной в функции g(). Они не создают недоразумений, потому что принадлежат разным областям видимости: переменная x, объявленная в функции f(), не видна извне функции f(), а переменная x, объявленная в функции g(), не видна извне функции g(). Два противоречащих друг другу объявления в одной и той же области видимости создают коллизию (clash). Аналогично, переменная f объявлена и используется в функции g() и (очевидно) не является функцией f().

Рассмотрим логически эквивалентный, но более реальный пример использования локальной области видимости.

int max(int a, int b) // функция max является глобальной;

                      // а переменные a и b — локальными

{

  return (a>=b) ? a : b;

}

int abs(int a)        // переменная a, не имеющая отношения

                      // к функции max()

{

  return (a<0) ? –a : a;

}

Функции max() и abs() принадлежат стандартной библиотеке, поэтому их не нужно писать самому. Конструкция ?: называется арифметической инструкцией if (arithmetic if), или условным выражением (conditional expression). Значение инструкции (a>=b)?a:b равно a, если a>=b, и b — в противном случае. Условное выражение позволяет не писать длинный код наподобие следующего:

int max(int a, int b) // функция max является глобальной;

                      // а переменные a и b — локальными

{

  int m; // переменная m является локальной

  if (a>=b)

    m = a;

  else

   m = b;

  return m;

}

 

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

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

// здесь переменные r, i и v не видны

class My_vector {

 vector<int> v;           // переменная v принадлежит области

                          // видимости класса

public:

 int largest()

 {

  int r = 0;              // переменная r является локальной

                          // (минимальное неотрицательное целое число)

  for (int i = 0; i<v.size(); ++i)

    r = max(r,abs(v[i])); // переменная i принадлежит

                          // области видимости цикла

                          // здесь переменная i не видна

  return r;

 }

                          // здесь переменная r не видна

}

// здесь переменная v не видна

int x;           // глобальная переменная — избегайте по возможности

int y;

int f()

{

  int x;         // локальная переменная, маскирующая глобальную

                 // переменную x

  x = 7;         // локальная переменная x

  {

    int x = y;   // локальная переменная x инициализируется

                 // глобальной переменной y, маскируя локальную

                 // переменную x, объявленную выше

  ++x;           // переменная x из предыдущей строки

  }

  ++x;           // переменная x из первой строки функции f()

  return x;

}

Если можете, избегайте ненужных вложений и сокрытий. Помните девиз: “Будь проще!”

Чем больше область видимости имени, тем длиннее и информативнее должно быть ее имя: хуже имен x, y и z для глобальных переменных не придумаешь. Основная причина, по которой следует избегать глобальных переменных, заключается в том, что трудно понять, какие функции изменяют их значения. В больших программах практически невозможно понять, какие функции изменяют глобальную переменную. Представьте себе: вы пытаетесь отладить программу, и выясняется, что глобальная переменная принимает неожиданное значение. Какая инструкция присвоила ей это значение? Почему? В какой функции? Как это узнать?

Функция, присвоившая неправильное значение данной переменной, может находиться в исходном файле, который вы никогда не видели! В хорошей программе может быть лишь несколько (скажем, одна или две) глобальных переменных. Например, калькулятор, описанный в главах 6 и 7, содержит две глобальные переменные: поток лексем ts и таблицу символов names.

Обратите внимание на то, что большинство конструкций в языке С++ создают вложенные области видимости.

• Функции в классах: функции-члены (раздел 9.4.2).

class C {

public:

 void f();

 void g()    // функция-член может быть определена в классе

 {

   // ...

 }

   // ...

   void C::f() // определение функции-члена за пределами класса

 {

   // ...

 }

Это наиболее типичный и полезный вариант.

• Классы в других классах: члены-классы (или вложенные классы).

class C {

public:

  struct M {

    // ...

  };

  // ...

};

Это допустимо только в сложных классах; помните, что в идеале класс должен быть маленьким и простым.

• Классы в функциях: локальные классы.

void f()

{

  class L {

    // ...

  };

  // ...

}

 

 Избегайте таких конструкций; если вам нужен локальный класс, значит, ваша функция слишком велика.

• Функции в других функциях: локальные функции (или вложенные функции).

void f()

{

  void g() // незаконно

  {

    // ...

  }

  // ...

}

В языке С++ это не допускается;

1 ... 82 83 84 85 86 87 88 89 90 ... 337
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп.
Книги, аналогичгные Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Оставить комментарий