Попробуйте часть кода до слова main заменить на #include "stdafx.h" //1 #include <iostream> //2 using namespace std; //3 |
Классы. Создание новых типов данных
14.7. Конструкторы и деструкторы (резюме)
При создании классов с новыми типами данных системы программирования на базе языка C++ облегчают работу программиста тем, что автоматически создают средства для объявления объектов нового типа, их инициализации и уничтожения. Эти средства получили название конструкторов (создателей) и деструкторов (разрушителей).
Создание объекта в соответствии с описанием данных в классе сводится к выделению ресурсов (как правило, речь идет об участке оперативной памяти) для хранения объекта и инициализации полей данных. К числу наиболее характерных методов инициализации участков памяти, которые не зависят от специфики задач, относятся три следующие процедуры:
- очистка выделенной памяти (для числовых данных это соответствует записи нулей, для строковых данных – записи пустых строк);
- заполнение выделенных полей константами, указанными при объявлении объекта;
- копирование в поля нового объекта содержимого полей ранее объявленного объекта.
В случае необходимости программист может включить в свой класс указанные конструкторы:
#include <iostream.h> class B { int x; public: B(){x=0; cout<<"Def_Constr_B "<<this<<endl;} B(int y){x=y; cout<<"Init_Constr_B "<<this<<endl;} B(const B &z){x=z.x; cout<<"Copy_Constr_B "<<this<<endl;} int get_x(){return x;} ~B(){cout<<"Destr B"<<this<<endl;} }; void main() { B q1; //обращение к конструктору по умолчанию B q2(2); //обращение к конструктору инициализации B q3(q2); //прямое обращение к конструктору копирования B q4=q1; //косвенное обращение к конструктору копирования cout<<"q1="<<q1.get_x()<<endl; cout<<"q2="<<q2.get_x()<<endl; cout<<"q3="<<q3.get_x()<<endl; cout<<"q4="<<q4.get_x()<<endl; } //=== Результат работы === Def_Constr_B 0012FF88 //конструктор по умолчанию, адрес q1.x Init_Constr_B 0012FF84 //конструктор инициализации, адрес q2.x Copy_Constr_B 0012FF80 //конструктор копирования, адрес q3.x Copy_Constr_B 0012FF7C //конструктор копирования, адрес q4.x q1=0 q2=2 q3=2 q4=0 //Деструктор вызывается автоматически при выходе из блока Destr B 0012FF7C //уничтожение объекта q4 Destr B 0012FF80 //уничтожение объекта q3 Destr B 0012FF84 //уничтожение объекта q2 Destr B 0012FF88 //уничтожение объекта q114.3.
Если программист не включает в свой класс ни одного конструктора, то компилятор автоматически вписывает ему конструктор по умолчанию (в отличие от приведенного выше системный конструктор не чистит память) и конструктор копирования.
Специфика конструкторов заключается в следующем:
- имя конструктора совпадает с именем класса;
- перед именем конструктора отсутствует указание о типе возвращаемого значения;
- как и любая другая функция, конструктор может иметь список параметров, передаваемых ему при объявлении объекта. В заголовке конструктора могут присутствовать параметры по умолчанию. У стандартного конструктора по умолчанию список параметров пуст;
- программист имеет право написать столько конструкторов, сколько он считает нужным. Но как только он включил в описание класса тело хотя бы одного конструктора, компилятор никаких своих конструкторов добавлять не будет.
Каждый класс обязан иметь хотя бы один общедоступный конструктор, в противном случае программа не сможет объявить ни один объект новой структуры.
Пример нестандартного конструктора по умолчанию, который пришлось написать нам самим, мы видели в классе Rational – с нулевым знаменателем работать было бы нельзя.
В отличие от конструкторов, создающих объекты, деструктор их уничтожает, освобождая ресурсы, выделенные для хранения объекта. Деструктор у класса может быть только один. Если программист не напишет свой деструктор, который производит дополнительные нестандартные действия, то компилятор подключит системный деструктор. Имя деструктора начинается с "тильды", которая предшествует имени класса. Параметров у деструктора нет:
Rational v1; //объявление с помощью конструктора по умолчанию Rational v2(1,2); //использование конструктора инициализации Rational v3(v2); //использование конструктора копирования ~Rational(); //деструктор
Явно к деструктору обращаться не приходится, т.к. он вызывается автоматически при выходе из блока программы, в котором был создан объект.
Иногда деструктор класса приходится писать. Необходимость в этом возникает в тех случаях, когда деструктор должен выполнить некоторые нестандартные действия. Например, если в классе создается динамический массив, то для его уничтожения приходится разрушать каждый элемент массива:
class array { int size; char *p; public: array(int dim); //конструктор создания динамического массива ~array(){ delete [] p; } //деструктор разрушения массива ......................... }; array::array(int dim) //тело конструктора { p=new char[dim]; //запрос памяти под динамический массив if(!p) //если память не выделена { cout<<"Allocation error"; exit(1); } size=dim; }