Конструктор и деструктор классов в C++

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

Тут нам как раз сможет помочь конструктор класса. Кстати, конструктор (от слова construct — создавать) – это специальный метод класса, который предназначен для инициализации элементов класса некоторыми начальными значениями.

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

Важно запомнить:

  1. конструктор и деструктор, мы всегда объявляем в разделе public;
  2. при объявлении конструктора, тип данных возвращаемого значения не указывается, в том числе — void!!!;
  3. у деструктора также нет типа данных для возвращаемого значения, к тому же деструктору нельзя передавать никаких параметров;
  4. имя класса и конструктора должно быть идентично;
  5. имя деструктора идентично имени конструктора, но с приставкой ~ ;
  6. В классе допустимо создавать несколько конструкторов, если это необходимо. Имена, согласно пункту 2 нашего списка, будут одинаковыми. Компилятор будет их различать по передаваемым параметрам (как при перегрузке функций). Если мы не передаем в конструктор параметры, он считается конструктором по умолчанию;
  7. Обратите внимание на то, что в классе может быть объявлен только один деструктор;

Сразу хочу привести пример, который доступно покажет, как работает конструктор:

# include <iostream>
using namespace std;

class AB //класс
{
    private:
    int a;
    int b;
    public:
    AB()	//это конструктор:	1) у конструктора нет типа возвращаемого значения! в том числе void!!!
    //	 2) имя должно быть таким как и у класса (в нашем случае AB)
    {
        a = 0;//присвоим начальные значения переменным
        b = 0;
        cout << "Работа конструктора при создании нового объекта: " << endl;//и здесь же их отобразим на экран
        cout << "a = " << a << endl;
        cout << "b = " << b << endl << endl;
    }

    void setAB() // с помощью этого метода изменим начальные значения заданные конструктором
    {
        cout << "Введите целое число а: ";
        cin >> a;
        cout << "Введите целое число b: ";
        cin >> b;
    }

    void getAB() //выведем на экран измененные значения
    {
        cout << "a = " << a << endl;
        cout << "b = " << b << endl << endl;
    }
};

int main()
{
    setlocale(LC_ALL, "rus");

    AB obj1;	 //конструктор сработает на данном этапе (во время создания объекта класса)

    obj1.setAB();	//присвоим новые значения переменным
    obj1.getAB();	//и выведем их на экран

    AB obj2;	 //конструктор сработает на данном этапе (во время создания 2-го объекта класса)
return 0;
}

Результат работы программы:

CppStudio.com
Работа конструктора при создании нового объекта: 
a = 0
b = 0

Введите целое число а: 34
Введите целое число b: 67
a = 34
b = 67

Работа конструктора при создании нового объекта: 
a = 0
b = 0

Как видно из результата работы программы, конструктор срабатывает сразу, при создании объектов класса, поэтому, явно вызывать конструктор не нужно, он сам «приходит» :)

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

Рассмотрим еще один пример, это все та же программа, только в код внесены некоторые изменения. Тут же покажем принцип работы деструктора:

# include <iostream>
using namespace std;

class AB //класс
{
    private:
    int a;
    int b;

    public:
    AB(int A, int B) //эти параметры мы передадим при создании объекта в main
    {
        a = A;//присвоим нашим элементам класса значения параметров
        b = B;
        cout << "Тут сработал конструктор, который принимает параметры: " << endl;//и здесь же их отобразим на экран
        cout << "a = " << a << endl;
        cout << "b = " << b << endl << endl;
    }

    void setAB()
    {
        cout << "Введите целое число а: ";
        cin >> a;
        cout << "Введите целое число b: ";
        cin >> b;
    }

    void getAB()
    {
        cout << "a = " << a << endl;
        cout << "b = " << b << endl << endl;
    }

    ~AB() // это деструктор. не будем заставлять его чистить память, пусть просто покажет где он сработал
    {
        cout << "Тут сработал деструктор" << endl;
    }
};

int main()
{
setlocale(LC_ALL, "rus");

AB obj1(100, 100);	//передаем конструктору параметры

obj1.setAB();	//присвоим новые значения переменным
obj1.getAB();	//и выведем их на экран

AB obj2(200, 200);	//передаем конструктору параметры
}

Смотрим результат работы программы:

CppStudio.com
Тут сработал конструктор, который принимает параметры: 
a = 100
b = 100

Введите целое число а: 333
Введите целое число b: 333
a = 333
b = 333

Тут сработал конструктор, который принимает параметры: 
a = 200
b = 200

Тут сработал деструктор
Тут сработал деструктор

Деструктор срабатывает в тот момент, когда завершается работа программы и уничтожаются все данные. Мы его не вызывали – он сработал сам. Как видно, он сработал 2 раза, так как и конструктор. Уже от себя добавлю, что, в первую очередь, он удалил второй созданный объект (где a = 200, b = 200), а затем первый (где a = 100, b = 100). «Последним пришёл — первым вышел».

Практика

К сожалению, для данной темы пока нет подходящих задач. Если у вас есть таковые на примете, отправте их по адресу: admin@cppstudio.com. Мы их опубликуем!

Автор: Marienko L.
Дата: 05.12.2013
Поделиться:

Комментарии

  1. Dharma Cdr

    Подскажите пожалуйста. Есть такой интересный момент:

    1. Объявление С-строк. Отрабатывает конструктор, выделяя в динамической памяти место и заполняет все позиции »

    ModCString myStr(10); 
    
    ModCString myStr4(20);

    2. Инициализирую строки с клавиатуры

    //2. Str manual init
    cout << "Type the text (maximum " << myStr.GetSize() << ") symbols: \n ->";
    myStr.InputStr();
    
    cout << "Type the text (maximum " << myStr.GetSize() << ") symbols: \n ->";
    myStr4.InputStr();
    
    С помощью перегруженного оператора "=" присваиваю одну строку другой: 
    
    myStr = myStr4; Здесь предварительно, освобождается память, взятая под myStr строку и создается новая размером как myStr4, и выполняется посимвольное копирование.

     

    Проблема возникает, при отработке деструктора, т.к. он пытается освободить память, а расположении строки myStr в памяти уже было изменено. При этом в области видимости деструктора «новое» расположение моей строки прекрасно видно, но отрабатывает с ошибкой «HEAP CORRUPTION» Как обойти эту проблему?

  2. Nicolai Zdravcov

    Я не могу понять одно…Обязательно ли указывать конструктор в классе? Насколько я понял указывать его не обязательно, но это дурной тон програмирования. Если нет необходимости, то деструктор указывать необязательно.

    Теперь вопрос следующий, если нет необходимости в конструкторе допустимо ли его указывать пустым?

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

    • Vova Denys

      конструктор по умолчанию создается автоматически (не явно).
      в конструкторе происходит инициализация переменных и она происходит быстрее чем метод где присваиваются значения переменным.

       

  3. blablabla

    слишком размытое понятие «Конструктора», после 5-ти раз перечитывания данной статьи я так и ничего не понял.

Оставить комментарий

Вы должны войти, чтобы оставить комментарий.