[H-L-L.ru]

Форма входа

Меню сайта

Categories
1. Основы работы в среде C++ Builder.Основы языка Си++ [9]
2. Операторы ветвления и операторы передачи управления [4]
3. Операторы цикла и операторы передачи управления [5]
4. Одномерные массивы [3]
5. Многомерные массивы [3]
6. Указатели.Динамическое распределение памяти [6]
7. Отладка программы [3]
8. Функции [8]
9. Строки [5]
10. Функция Main [2]
11. Типы данных,определяемые пользователем [5]
12. Потоки ввода/вывода [7]
13. Основы объектно-ориентированного программирования [5]
Приложения [11]

Главная » Статьи » Лекции по C++ » 13. Основы объектно-ориентированного программирования

3. Конструктор и деструктор
Конструктор и деструктор

При создании объектов одной из наиболее широко используемых операций, которую вы будете выполнять в ваших программах, является инициализация элементов данных объекта. Единственным способом, с помощью которого вы можете обратиться к частным элементам данных, является использование функций класса. Чтобы упростить процесс инициализации элементов данных класса, C++ использует специальную функцию, называемую конструктором, которая запускается для каждого создаваемого вами объекта. Подобным образом C++ обеспечивает функцию, называемую деструктором, которая запускается при уничтожении объекта. Таким образом:

• Конструктор представляет собой метод класса, который облегчает вашим программам инициализацию элементов данных класса при объявлении объекта.

• Конструктор имеет такое же имя, как и класс.

• Конструктор не имеет возвращаемого значения.

• Каждый раз, когда ваша программа создает переменную класса, C++ вызывает конструктор класса.

• Многие объекты могут распределять память для хранения информации; когда вы уничтожаете такой объект, C++ будет вызывать специальный деструктор, который может освобождать эту память, очищая ее после объекта.

• Деструктор имеет такое же имя, как и класс, за исключением того, что вы должны предварять его имя символом тильды (~).

• Деструктор не имеет возвращаемого значения.

Термины конструктор и деструктор не должны вас пугать. Вместо этого представьте конструктор как функцию, которая помогает вам строить (конструировать) объект. Подобно этому, деструктор представляет собой функцию, которая помогает вам уничтожать объект. Деструктор обычно используется, если при уничтожении объекта нужно освободить память, которую занимал объект.

Создание простого конструктора

Конструктор представляет собой метод класса, который имеет такое же имя, как и класс. Например, если вы используете класс с именем employee, конструктор также будет иметь имя employee. Подобно этому, для класса с именем dogs конструктор будет иметь имя dogs. Если ваша программа определяет конструктор, C++ будет автоматически вызывать его каждый раз, когда вы создаете объект. Следующая программа CONSTRUC.CPP создает класс с именем employee. Программа также определяет конструктор с именем employee, который присваивает начальные значения объекту. Однако конструктор не возвращает никакого значения, несмотря на то, что он не объявляется как void. Вместо этого вы просто не указываете тип возвращаемого значения:

class employee {

  public:

    employee(char *, long, float); // объявление конструктора

    void show_employee(void);

    int change_salary(float);

    long get_id(void);

  private:

    char name[64];

    long employee_id;

    float salary;

};


В вашей программе вы просто определяете конструктор так же, как любой другой метод класса:

employee::employee(char *name, long employee_id, float salary)

{

strcpy(employee::name, name);

employee::employee_id = employee_id;

if (salary < 50000.0)

   employee::salary = salary;

else

employee::salary = 0.0; // Недопустимый оклад

}

Как видите, конструктор не возвращает значение вызвавшей функции. Для него также не используется тип void. В данном случае конструктор использует оператор глобального разрешения и имя класса перед именем каждого элемента. Ниже приведена реализация программы CONSTRUC.CPP:

#include <iostream.h>

#include <string.h>

class employee {

public:

  employee (char *, long, float);

  void show_employee(void);

  int change_salary ( float );

  long get_id(void);

private :

  char name [64] ;

  long employee_id;

  float salary;

};

employee:: employee (char *name, long employee_id, float salary)

{

strcpy ( employee :: name , name ) ;

employee :: employee_id = employee_id;

if (salary < 50000.0)

  employee :: salary = salary;

else

employee :: salary = 0.0;  // Недопустимый оклад

}


void employee:: show_employee (void)

{

cout << "Служащий: " << name << endl;

cout << "Номер служащего: " << employee_id << endl;

cout << "Оклад: " << salary << endl;

}


void main (void)

{

employee worker ( "Happy Jamsa", 101, 10101.0);

worker . show_employee ( ) ;

}


Обратите внимание, что за объявлением объекта worker следуют круглые скобки и начальные значения, как и при вызове функции. Когда вы используете конструктор, передавайте ему параметры при объявлении объекта:

employee worker ( "Happy Jamsa", 101, 10101.0);

Если вашей программе потребуется создать несколько объектов employee, вы можете инициализировать элементы каждого из них с помощью конструктора, как показано ниже:

employee worker ( "Happy Jamsa", 101, 10101.0);

employee secretary ("John Doe", 57, 20000.0);

employee manager ( "Jane Doe", 1022, 30000.0);



Конструкторы и параметры по умолчанию


C++ позволяет указывать значения по умолчанию для параметров функции. Если пользователь не указывает каких-либо параметров, функция будет использовать значения по умолчанию. Конструктор не является исключением; ваша программа может указать для него значения по умолчанию так же, как и для любой другой функции. Например, следующий конструктор employee использует по умолчанию значение оклада равным 10000.0, если программа не указывает оклад при создании объекта. Однако программа должна указать имя служащего и его номер:

 

employee:: employee (char *name, long employee_id, float salary =  10000.00)

{

strcpy ( employee :: name , name ) ;

employee :: employee_id = employee_id;

if (salary < 50000.0)

employee :: salary = salary;

else

employee :: salary  =  0.0;  //  Недопустимый оклад

}


Перегрузка конструкторов

Как вы уже знаете, C++ позволяет вашим программам перегружать определения функций, указывая альтернативные функции для других типов параметров. C++ позволяет вам также перегружать конструкторы. Следующая программа CONSOVER.CPP перегружает конструктор employee. Первый конструктор требует, чтобы программа указывала имя служащего, номер служащего и оклад:

employee:: employee (char *name, long employee_id, float salary)

{

strcpy ( employee :: name , name ) ;

employee :: employee_id = employee_id;

if (salary < 50000.0)

  employee :: salary = salary;

else

employee :: salary = 0.0;  // Недопустимый оклад

}


Второй конструктор запрашивает пользователя ввести требуемый оклад, если программа не указывает его:

employee::employee(char *name, long employee_id)

{

strcpy(employee::name, name);

employee::employee_id = employee_id;

do {

       cout << "Введите оклад для " << name <<" меньше $50000: ";

       cin >> employee: :salary;

     }

while (salary >= 50000.0);

}


Внутри определения класса программа должна указать прототипы для обоих конструкторов, как показано ниже:

class employee {

public:

   employee (char *, long, float) ;   // Прототипы перегруженных конструкторов

   employee (char *, long);            // Прототипы перегруженных конструкторов

   void show_employee(void) ;

   int change_salary ( float );

   long get_id(void) ;

private :

char name [64] ;

long employee_id;

float salary;

}


Ниже приведена реализация программы CONSOVER.CPP:

# include <iostream.h>

# include <string.h>

class employee {

public:

   employee (char *, long, float);

   employee (char *, long);

   void show_employee(void) ;

   int change_salary( float) ;

   long get_id(void) ;

private :

char name [64] ;

long employee_id;

float salary;};

 

employee:: employee (char *name, long employee_id,float salary)

{

strcpy ( employee :: name , name ) ;

employee :: employee_id = employee_id;

if (salary < 50000.0) employee::salary = salary;

else      // Недопустимый оклад

employee::salary = 0.0;}

 

employee::employee(char *name, long employee_id)

{

strcpy(employee::name, name);

employee::employee_id = employee_id;

do {

       cout << "Введите оклад для " << name <<" меньше $50000: ";

       cin >> employee: :salary;

     }

while (salary >= 50000.0);

}

 

void employee::show_employee(void)

{

cout << "Служащий: " << name << endl;

cout << "Номер служащего: " << employee_id << endl;

cout << "Оклад: " << salary << endl;

}

 

void main(void)

{

employee worker("Happy Jamsa", 101, 10101.0);

employee manager("Jane Doe", 102);

worker.show_employee();

manager.show_employee();

}


Если вы откомпилируете и запустите эту программу, на вашем экране появится запрос ввести оклад для Jane Doe. Когда вы введете оклад, программа отобразит информацию об обоих служащих.

Конструктор копирования

Конструктор копирования создает объект класса, копируя при этом данные из уже существующего объекта данного класса.

Конструктор копии является конструктором специального вида, который принимает в качестве параметра ссылку или константную ссылку на объект данного класса. Он автоматически вызывается компилятором, когда вновь создаваемый объект инициализируется значениями существующего объекта.

Пример:

class Coord

{int x,y;

public:

Coord(const Coord & src)   //объявление конструктора копирования

};

Coord:: Coord(const Coord & src)    // определение конструктора копирования

{

x = src.x;

y = src.y;

}

int main()

{ Coord ob1(2,9); //создание объекта 1

Coord ob2 = ob1; //копирование объекта 1 в объект 2

Coord ob3(ob1); // копирование объекта 1 в объект 3

….

return 0;

}


Если конструктор копирования специально не создавался, компилятор создает его по умолчанию. Этот конструктор вызывается в тех случаях, когда новый объект создается путем копирования существующего:

     при описании нового объекта с инициализацией другим объектом;

     при передаче объекта в функцию по значению;

     при возврате объекта из функции, а также при обработке исключений.

Такой конструктор выполняет поэлементное копирование полей.

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

Запишем конструктор копирования для класса monstr. Поскольку в нем есть поле name, содержащее указатель на строку символов, конструктор копирования должен выделять память под новую строку и копировать в нее исходную:

class monstr

{

      int health, ammo;

      color skin;

      char *name;

public:

      monstr(int he = 100, int am   = 10);

      monstr (color sk);

      monstr(char * nam) ;

      int get_health(){ return health:}

      int get_ammo(){ return ammo;}

}

……………………

monstr: :monstr(const monstr &M)

{

 if (M.name)

   {

      name = new char [strlen(M.name) + 1];

      strcpy(name, M.name);

    }

 else name = 0;

 health = M. health;

 ammo = M.ammo;

 skin = M.skin;

}

…………

monstr Vasia (blue);

monstr Super = Vasia;       // Работает конструктор копирования

monstr *m = new monstr ("Ork");

monstr Green = *m;        // Работает конструктор копирования


Деструктор


Деструктор – это особый вид метода, применяющийся для освобождения памяти, занимаемой объектом. Деструктор вызывается автоматически, когда объект выходит из области видимости:

для локальных объектов – при выходе из блока, в котором они объявлены;

для глобальных – как часть процедуры выхода из main при завершении программы;

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

Автоматический вызов деструктора объекта при выходе из области действия указателя на него не производится.

Имя деструктора начинается с тильды (~), непосредственно за которой следует имя класса:

~class_name(void)

{

Операторы деструктора

}


В отличие от конструктора вы не можете передавать параметры деструктору.

Следующий код определяет деструктор для класса employee:

void employee:: ~employee (void)

{

cout << "Уничтожение объекта для " << name << endl;

}


В данном случае деструктор просто выводит на ваш экран сообщение о том, что C++ уничтожает объект.

Деструктор:

не имеет аргументов и возвращаемого значения;

не может быть объявлен как const или static;

не наследуется;

может быть виртуальным;

указатель на деструктор определить нельзя.

Если деструктор явным образом не определен, компилятор автоматически создает пустой деструктор.

Описывать в классе деструктор явным образом требуется в случае, когда объект содержит указатели на память, выделяемую динамически – иначе при уничтожении объекта память, на которую ссылались его поля-указатели, не будет помечена как свободная.

Деструктор для класса monstr должен выглядеть так:

monstr::~monstr() {delete [] name;}

Деструктор можно вызвать явным образом путем указания полностью уточненного имени, например:

monstr *m=new monstr;  //создается динамический объект

m -> ~monstr();  // явно вызывается деструктор


Это может понадобиться для объектов, которым с помощью операции new выделялся конкретный адрес памяти. Без необходимости явно вызывать деструктор объекта не рекомендуется.

Конструкторы и деструкторы в С++ вызываются автоматически, что гарантирует правильное создание и удаление объектов класса.


Источник: создание простого конструктора параметры по умолчанию копирования деструктор c++

Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

Полная версия сайта