double arrow

Перегруженные конструкторы


Было бы удобно производить инициализацию переменных класса Distance в мо­мент их создания, то есть использовать объявления типа

Distance width(5, 6.25):

где определяется объект width, сразу же инициализируемый значениями 5 и 6.25 для футов и дюймов соответственно.

Чтобы сделать это, вызовем конструктор следующим образом:

Distance(int ft, float in) : feet(ft). inches(in)

{ }

Мы инициализируем поля feet и inches теми значениями, которые передают­ся конструктору в качестве аргументов.

Тем не менее, мы хотим сохранить возможность определять переменные класса Distance без инициализации, подобно тому, как мы делали в программе ENGL0BJ.

Distance distl. dist2:

В программе ENGL0BJ не было конструктора, но определения работали без ошибок. Почему же они работали без конструктора? Это объясняется тем, что компилятор автоматически встраивает в программу конструктор без парамет­ров, который и создает переменные класса, несмотря на то, что явного определе­ния конструктора мы не делали. Такой конструктор без параметров называется конструктором по умолчанию. Если бы конструктор по умолчанию не создавал­ся автоматически, то мы не смогли бы определять переменные классов, в кото­рых отсутствует конструктор.




Зачастую нам хотелось бы, чтобы начальные значения полям объекта при­сваивались также и в конструкторе без параметров. Если возложить эту функ­цию на конструктор по умолчанию, то мы не сможем узнать, какими значения­ми были инициализированы поля. Если же для нас важно, какими значениями будут инициализироваться поля объекта класса, то нам следует явно опреде­лить конструктор. В программе ENGLC0N мы поступаем подобным образом:

Distance() : feet(0). inches(0.0) //конструктор по умолчанию

{ }   //тело функции пусто, никаких действий не производится

Члены класса инициализируются константными значениями, в данном слу­чае целым значением 0 для переменной feet и вещественным значением 0.0 для переменной inches. Значит, мы можем использовать объекты, инициализиру­емые с помощью конструктора без параметров, будучи уверенными в том, что поля объекта имеют нулевые, а не другие, случайные, значения.

Теперь у нас имеется два явно определенных конструктора с одним и тем же именем Distance(), и поэтому говорят, что конструктор является перегруженным. Какой из этих двух конструкторов исполняется во время создания нового объек­та, зависит от того, сколько аргументов используется при вызове:

Distance length: //вызывает первый конструктор

Distance width(11, 6.0): //вызывает второй конструктор

Определение методов класса вне класса

До сих пор мы всегда определяли методы класса внутри самого класса. На самом деле это не является обязательным. В примере ENGLC0N метод add_dist() опреде­лен вне класса DistanceQ. Внутри определения класса содержится лишь прототип функции add_dist():



void add_dist(Distance, Distance):

Такая форма означает, что функция является методом класса, однако ее оп­ределение следует искать не внутри определения класса, а где-то в другом месте листинга.

В примере ENGLC0N функция add_dist() определена позже, чем класс Distance(). Ее код взят из программы ENGLSTRC:

void Distance::add_dist(Distance d2, Distance d3) {

inches = d2.inches + d3.inches; // сложение дюймов

feet =0;     //с возможным заемом

if(inches >= 12.0) // если число дюймов больше 12.0.

{      //то уменьшаем число дюймов

inches -= 12.0;    // на 12.0 и увеличиваем

feet++;      // число футов на 1

}

feet +=d2.feet + d3.feet: // сложение футов

}

 

Заголовок функции содержит не встречавшиеся нам ранее синтаксические элементы. Перед именем функции add_dist() стоит имя класса Distance и новый символ ::. Этот символ является знаком операции глобального разрешения. Такая форма записи устанавливает взаимосвязь функции и класса, к которой относит­ся эта функция. В данном случае запись Distance::add_list() означает, что функ­ция add_dist() является методом класса Distance.

 

 







Сейчас читают про: