Выбрать главу

В C++ как локальные, так и глобальные переменные можно инициализировать во время выполнения программы. Этот процесс иногда называют динамической инициализацией. До сих пор в большинстве инструкций инициализации, представленных в этой книге, использовались константы. Однако переменную можно также инициализировать во время выполнения программы, используя любое С++-выражение, действительное на момент объявления этой переменной. Это означает, что переменную можно инициализировать с помощью других переменных и/или вызовов функций при условии, что в момент выполнения инструкции объявления общее выражение инициализации имеет действительное значение. Например, следующие варианты инициализации переменных абсолютно допустимы в C++,

int n = strlen(str);

double arc = sin(theta);

float d = 1.02 * count / deltax;

Применение динамической инициализации к конструкторам

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

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

Например, в следующей версии программы таймера для создания двух объектов b и с используется динамическая инициализация.

// Демонстрация динамической инициализации.

#include <iostream>

#include <cstdlib>

#include <ctime>

using namespace std;

class timer{

  int seconds;

 public:

  // секунды, задаваемые в виде строки

  timer(char *t) { seconds = atoi(t); }

  // секунды, задаваемые в виде целого числа

  timer(int t) { seconds = t; }

  // время, задаваемое в минутах и секундах

  timer(int min, int sec) { seconds = min*60 + sec; }

  void run();

};

void timer::run()

{

 clock_t t1;

 t1 = clock();

 while((clock()/CLOCKS_PER_SEC - t1/CLOCKS_PER_SEC)<seconds);

 cout << "\a"; // звуковой сигнал

}

int main()

{

 timer a(10);

 a.run();

 cout << "Введите количество секунд: ";

 char str[80];

 cin >> str;

 timer b(str); // инициализация в динамике

 b.run();

 cout << "Введите минуты и секунды: ";

 int min, sec;

 cin >> min >> sec;

 timer с(min, sec); // инициализация в динамике

 c.run();

 return 0;

}

Как видите, объект a создается с использованием целочисленной константы. Однако основой для создания объектов b и c служит информация, вводимая пользователем. Поскольку для объекта b пользователь вводит строку, имеет смысл перегрузить конструктор timer() для приема строк. Объект c также создается во время выполнения программы с использованием данных, вводимых пользователем. Поскольку в этом случае время вводится в виде минут и секунд, для построения объекта c логично использовать формат конструктора, принимающего два аргумента. Трудно не согласиться с тем, что наличие множества форматов инициализации избавляет программиста от выполнения дополнительных преобразований при инициализации объектов.