Читаем Программирование полностью

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() // незаконно

  {

    // ...

  }

  // ...

}

В языке С++ это не допускается; не поступайте так. Компилятор выдаст ошибку.

• Блоки в функциях и других блоках: вложенные блоки.

void f(int x, int y)

{

  if (x>y) {

    // ...

  }

  else {

    // ...

  {

    // ...

  }

    // ...

  }

}

Вложенные блоки неизбежны, но они свидетельствуют о завышенной сложности программы и уязвимы для ошибок.

В языке C++ существует еще одно средство — namespace, которое используется исключительно для разграничения областей видимости (раздел 8.7).

  Следите за выравниванием фигурных скобок, обозначающих вложение. Если бы выравнивания не было, код было бы невозможно читать. Рассмотрим пример.

// опасно уродливый код

struct X {

void f(int x) {

struct Y {

int f() { return 1; } int m; };

int m;

m=x; Y m2;

return f(m2.f()); }

int m; void g(int m) {

if (m) f(m+2); else {

g(m+2); }}

X() { } void m3() {

}

void main() {

X a; a.f(2);}

};

Неудобочитаемый код обычно скрывает ошибки. Если вы используете интегрированные среды разработки программ, то они автоматически выравнивают фигурные скобки (в соответствии со своими установками). Кроме того, существуют “программы изящного форматирования”, которые переформатируют исходный код в файле (часто предлагая пользователю выбор). Однако окончательная ответственность за удобочитаемость кода лежит на его авторе. 

<p id="AutBody_Root140"><strong>8.5. Вызов функции и возврат значения</strong></p>

  Функции позволяют нам выражать действия и вычисления. Если мы хотим сделать что-то, заслуживающее названия, то пишем функцию. В языке С++ есть операторы (такие как + и *), с помощью которых можно вычислить новые значения по операндам, входящим в выражение, и инструкции (такие как for и if), позволяющие управлять порядком вычислений. Для того чтобы организовать код из этих примитивов, у нас есть функции.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже