ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 6) онлайн
Объекты в качестве аргументов функций
В следующей нашей программе мы внесем улучшения в пример ENGLOBJ, а также продемонстрируем несколько новых аспектов создания классов: перегрузку кон- структоров, определение методов класса вне класса и, возможно, самое важное —
использование объектов в качестве аргументов функций. Рассмотрим программу ENGLCON:
// englcon.cpp
// constructors,adds objects using member function
#include <iostream>
using namespace std;
//////////////////////////////////////////////////////////
class Distance // длина в английской системе
{
private:
int feet;
float inches;
public: // конструктор без аргументов
Distance() : feet(0),inches(0.0)
{ }
// конструктор с двумя аргументами
Distance(int ft,float in) : feet(ft),inches(in)
{ }
void getdist() // ввод длины пользователем
{
cout << "\nВведите число футов: "; cin >> feet;
cout << "Введите число дюймов: "; cin >> inches;
}
void showdist() // вывод длины на экран
{ cout << feet << "\'-" << inches << '\"'; }
void add_dist( Distance, Distance ); // прототип
};
//--------------------------------------------------------
// сложение длин d1 и d2
void Distance::add_dist(Distance dd1, Distance dd2)
{
inches = dd1.inches + dd2.inches; // сложение дюймов
feet = 0; // с возможным заемом
if(inches >= 12.0) // если число дюймов больше 12.0,
{ // то уменьшаем число дюймов
inches -= 12.0; // на 12.0 и увеличиваем
feet++; // число футов на 1
}
feet += dd1.feet + dd2.feet; // сложение футов
}
//////////////////////////////////////////////////////////
int main()
{
Distance dist1, dist3; // две длины
Distance dist2(11, 6.25); // определение и инициализация
dist1.getdist(); // ввод dist1
dist3.add_dist(dist1,dist2); // dist3 = dist1 + dist2
// вывод всех длин
cout << "\ndist1 = "; dist1.showdist();
cout << "\ndist2 = "; dist2.showdist();
cout << "\ndist3 = "; dist3.showdist();
cout << endl;
return 0;
}
Основной блок этой программы начинается с присвоения начальных значе- ний полям объекта dist2 класса Distance, после чего производится его сложение
с экземпляром dist1, инициализируемым пользователем. Затем на экран выво- дятся все три экземпляра класса Distance:
Введите число футов: 17 Введите число дюймов: 5.75 dist1 = 17'-5.75" dist2 = 11'-6.25" dist3 = 29'-О"
Рассмотрим теперь, как выполняются новые действия, включенные в программу.
Перегруженные конструкторы
Было бы удобно производить инициализацию переменных класса Distance в мо- мент их создания, то есть использовать объявления типа
Distance width(5, 6.25);
где определяется объект width, сразу же инициализируемый значениями 5 и 6.25 для футов и дюймов соответственно.
Чтобы сделать это, вызовем конструктор следующим образом:
Distance(int ft, float in) : feet(ft), inches(in) { }
Мы инициализируем поля feet и inches теми значениями, которые передают- ся конструктору в качестве аргументов.
Тем не менее, мы хотим сохранить возможность определять переменные клас- са Distance без инициализации, подобно тому, как мы делали в программе ENGLOBJ.
Distance dist1, dist2;
В программе ENGLOBJ не было конструктора, но определения работали без ошибок. Почему же они работали без конструктора? Это объясняется тем, что компилятор автоматически встраивает в программу конструктор без парамет- ров, который и создает переменные класса, несмотря на то, что явного определе- ния конструктора мы не делали. Такой конструктор без параметров называется конструктором по умолчанию. Если бы конструктор по умолчанию не создавал- ся автоматически, то мы не смогли бы определять переменные классов, в кото- рых отсутствует конструктор.
Зачастую нам хотелось бы, чтобы начальные значения полям объекта при- сваивались также и в конструкторе без параметров. Если возложить эту функ- цию на конструктор по умолчанию, то мы не сможем узнать, какими значения- ми были инициализированы поля. Если же для нас важно, какими значениями будут инициализироваться поля объекта класса, то нам следует явно опреде- лить конструктор. В программе ENGLCON мы поступаем подобным образом:
Distance() : feet(O), inches(O.O) //конструктор по умолчанию
{ } //тело функции пусто, никаких действий не производится
Члены класса инициализируются константными значениями, в данном слу- чае целым значением 0 для переменной feet и вещественным значением 0.0 для переменной inches. Значит, мы можем использовать объекты, инициализиру-
емые с помощью конструктора без параметров, будучи уверенными в том, что поля объекта имеют нулевые, а не другие, случайные, значения.
Теперь у нас имеется два явно определенных конструктора с одним и тем же именем Distance(), и поэтому говорят, что конструктор является перегруженным. Какой из этих двух конструкторов исполняется во время создания нового объек- та, зависит от того, сколько аргументов используется при вызове:
Distance length; //вызывает первый конструктор
Distance width(11, 6.0); //вызывает второй конструктор
Определение методов класса вне класса
До сих пор мы всегда определяли методы класса внутри самого класса. На самом деле это не является обязательным. В примере ENGLCON метод add_dist() опреде- лен вне класса Distance(). Внутри определения класса содержится лишь прототип функции add_dist();
void add_dist(Distance, Distance);
Такая форма означает, что функция является методом класса, однако ее оп- ределение следует искать не внутри определения класса, а где-то в другом месте листинга.
В примере ENGLCON функция add_dist() определена позже, чем класс Distance(). Ее код взят из программы ENGLSTRC главы 4:
void Distance::add_dist(Distance dd1, Distance dd2)
{
inches = dd1.inches + dd2.inches; // сложение дюймов
feet = 0; // с возможным заемом
if(inches >= 12.0) // если число дюймов больше 12.0,
{ // то уменьшаем число дюймов
inches -= 12.0; // на 12.0 и увеличиваем
feet++; // число футов на 1
}
feet += dd1.feet + dd2.feet; // сложение футов
}
Заголовок функции содержит не встречавшиеся нам ранее синтаксические элементы. Перед именем функции add_dist() стоит имя класса Distance и новый символ ::. Этот символ является знаком операции глобального разрешения. Такая форма записи устанавливает взаимосвязь функции и класса, к которой относит- ся эта функция. В данном случае запись Distance::add_dist() означает, что функ- ция add_dist() является методом класса Distance. Вышесказанное проиллюстри- ровано на рис. 6.5.
void Distance::add_dist(Distance dd1, Distance dd2)

Рис. 6.5. Операция разрешения
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
