Прежде чем продолжать дискуссию о перегрузке конструкторов, стоит обсудить важное различие между объявлением локальных переменных в С и тем способом, каким они могут быть объявлены в C++. В С необходимо объявлять все локальные переменные блока в самом начале этого блока. Нельзя объявлять переменные в блоке, где попало. Например, в С следующий фрагмент кода не является корректным:
void f()
{
int i;
i = 10;
int j;
/* ... */
}
Поскольку оператор присваивания i=10 попадает между двумя объявлениями i и j, то компилятор С выдаст ошибку и откажется компилировать эту функцию. Однако в C++ этот фрагмент абсолютно приемлем, и компилятор не обнаружит ошибки. В C++ локальная переменная может объявляться где угодно в блоке. Более того, она оказывается известной только тому коду, который следует после нее в блоке.
Ниже представлен другой пример, показывающий, каким способом локальные переменные могут объявляться в блоке при использовании языка C++:
#include <iostream.h>
#include <string.h>
int main()
{
int i;
i = 10;
int j = 100; // совершенно корректно в C++
cout << i*j << "\n";
cout << "Enter a string: ";
char str[80]; // также корректно в C++
cin >> str;
// вывод строки в обратном порядке
int k;
k = strlen(str) - 1;
while(к>=0) cout << str[k--];
return 0;
}
Все, что эта программа иллюстрирует, заключается в том, что, используя C++, можно объявлять локальные переменные где угодно в блоке кода. Поскольку философия языка C++ тесно связана с инкапсуляцией кода и данных, то имеет смысл объявлять переменные вблизи того кода, который их использует, а не при входе в блок. Здесь объявления i и j разделены между собой просто для иллюстрации. Однако можно видеть, каким образом локализация k вблизи соответствующего кода способствует инкапсуляции этой процедуры. Объявление переменных вблизи той точки, где они будут использованы, помогает избежать случайных побочных эффектов. Эта черта языка C++ также удобна при создании объектов, что иллюстрируется в следующем разделе.
Тот факт, что локальные переменные могут объявляться в любом месте блока кода, имеет большое значение для создания объектов. В реальных программах часто необходимо создавать объекты, инициализирующиеся значениями, появляющимися только в процессе выполнения программы. Имея возможность создавать объект после того, как эти величины становятся известными, можно избежать усложнения программы, которое возникает, когда сначала создается неинициализированный объект и лишь затем ему присваивается значение.
Для того чтобы увидеть преимущества, предоставляемые объявлением локальных объектов вблизи точки их первого использования, рассмотрим следующую версию программы timer. В ней два объекта b и c создаются, используя информацию, получаемую во время выполнения программы как раз перед первым использованием этих объектов. Программа также иллюстрирует преимущества перегрузки конструкторов, что позволяет реализовать различные способы инициализации.
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
class timer
{
//аналогично прошлому примеру
};
int main()
{
timer a(10);
a.run();
cout << "Enter number of seconds: ";
char str[80];
cin >> str;
timer b(str); // инициализация во время выполнения с помощью строки
b.run();
cout << "Enter minutes and seconds: ";
int min, sec;
cin >> min >> sec;
timer с(min, sec); /* инициализация во время выполнения с помощью минут и секунд */
c.run();
return 0;
}
Как можно видеть, объект а создан с использованием целой константы. В то же время объекты b и с созданы с использованием информации, введенной пользователем. Поэтому они не объявлялись до тех пор, пока эта информация не была известна. Таким образом, объекты b и с созданы с использованием данных, которые были сформированы как раз перед точкой их создания. Для объекта b в качестве таких данных выступает строка, в которой записаны секунды. Для объекта с данными служат два целых числа, с помощью которых вводятся минуты и секунды. Поскольку допустимы различные форматы инициализации, то нет необходимости выполнять преобразования данных от одного типа к другому при инициализации объекта. Из сказанного можно заключить, что целесообразно создавать объекты перед точкой их первого использования.