Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛР20-С++-16-сентября-2012 (1).doc
Скачиваний:
33
Добавлен:
12.11.2019
Размер:
1.18 Mб
Скачать

1.7. Методы класса

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

Пример 20.8.

Создать объект «параллелепипед». Вычислить объем. Поля объекта: длина, ширина, высота фигуры.

class СBox // объявление класса

{

public: // спецификатор доступа

double m_length; // поля – данные-члены класса

double m_width;

double m_height;

double Volume( ); // методы – функции-члены класса

// объявление метода – вычисление объема

};

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

Определение методов либо внутри класса, либо вне класса.

При внешнем определении в классе помещается только прототип метода:

тип имя_функции (спецификация_и_инициализация_параметров);

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

тип имя_класса::имя_функции (спецификация_формальных_параметров)

{тело_функции_члена_класса}

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

Методы можно перегружать. Перегрузка методов – одно из проявлений принципа полиморфизма.

1.8. Объявление объектов

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

Объявление экземпляров класса (объектов)

CBox mybox1, mybox2;

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

Для описания объекта класса (экземпляра класса) используется конструкция

имя_класса имя_объекта;

date today,my_birthday;

date *point = &today; // указатель на объект типа date

date clim[30]; // массив объектов

date &name = my_birthday; // ссылка на объект

Объявление указателей на класс

CBox *pbox;

pbox = &mybox1;

Динамическое выделение памяти для экземпляра класса (объекта)

CBox *pmybox = new CBox;

1.9. Конструктор

Недостатком рассмотренных ранее классов является отсутствие автоматической инициализации создаваемых объектов. Для каждого вновь создаваемого объекта необходимо было вызвать функцию типа set (как для класса complex) либо явным образом присваивать значения данным объекта. Однако для инициализации объектов класса в его определение можно явно включить специальную компонентную функцию, называемую конструктором.

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

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

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

Формат определения конструктора следующий:

имя_класса(список_форм_параметров){операторы_тела_конструктора}

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

Для конструкторов выполняются следующие правила:

  • для конструктора не указывается возвращаемый тип;

  • конструктор не может возвращать значение;

  • конструктор не наследуется;

  • для одного класса может существовать один или несколько конструкторов;

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

Конструкторы всегда называются по имени класса и не имеют типа возврата.

Имя конструктора по правилам языка С++ должно совпадать с именем класса. Такая функция автоматически вызывается при определении или размещении в памяти с помощью оператора new каждого объекта класса.

Пример.

сomplex(double re1 = 0.0,double im1 = 0.0){re = re1; im = im1;}

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

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

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

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

CBox mybox(1,2,3);

Конструктор имеет ряд особенностей:

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

  • Указатель на конструктор не может быть определен, и соответственно нельзя получить адрес конструктора.

  • Конструкторы не наследуются.

  • Конструкторы не могут быть описаны с ключевыми словами virtual, static, const, mutuable, valatile.

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

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

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

  • при возврате объекта из функции.

Компилятор предоставляет два типа конструкторов:

  • конструктор по умолчанию

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

Класс может иметь несколько конструкторов, которые можно перегружать.

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

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

Конструктор включается в состав класса в разделе public.

Так применительно к классу принтеров примера 20.7 конструктор имеет вид:

class Printer

{

public:

Printer(); //Конструктор

};

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

Printer :: Printer()

{

strcpy(model,"Canon_BJC250");

year=2000;

status=0;

}

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

int main(void)

{

Printer printer; //Конструктор инициализирует

//переменные объекта

printer.show();

return 0;

}

Пример 20.9.

Создать программу решения примера 20.7 с использованием конструктора.

Полный текст программы для примера 20.9:

//Пример 20.9

#include <iostream.h>

#include <conio.h>

class Printer

{

private:

char model[15]; //модель принтера

int year; //год выпуска

int status; //состояние принтера

public:

Printer(); //Конструктор

void init_printer(char* _model, int _year);

void set_print();

void stop_print();

void show();

};

void Printer::init_printer(char* _model,int _year)

{

strcpy(model,_model); //инициализация свойства model

year=_year; //инициализация свойства year

status=0; //начальное состояние - готов к печати

}

void Printer :: set_print()

{

if (!status) status=1;

}

void Printer :: stop_print()

{

status = 0;

}

void Printer :: show()

{

cout<<"Model: "<<model<<" year: "<<year<<" status: "<<status<<endl;

}

Printer :: Printer()

{

strcpy(model,"Canon_BJC250");

year=2000;

status=0;

}

int main()

{

Printer printer; //Конструктор инициализирует

//переменные объекта

printer.show();

cout << "\nНажмите любую клавишу..." ;

getch();

return 0;

}

При выполнении этой программы на экран будет выведено сообщение:

Model: Canon_BJC250 year: 2000 status: 0

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

Чтобы получать каждый раз объекты с новыми значениями свойств, используется конструктор с параметрами:

class Printer

{

public:

//Конструктор с параметрами

Printer(char* _model, int _year);

};

где _model – имя параметра, соответствующего значению модели, _year – имя параметра, соответствующего значению года.

Замечание. Имена параметрам могут быть даны любые, но удобно, когда имена параметров совпадают с названиями соответствующих свойств, отличаясь от них лишь первым символом _ (знак подчеркивания). Такой прием позволяет не запутаться при написании конструктора. Однако применять его можно лишь в том случае, если компилятор позволяет ставить знак _ в начале идентификатора.

Теперь конструктор будет выглядеть так:

Printer :: Printer(char* _model, int _year)

{

strcpy(model, _model);

year=_year;

status=0;

}

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

int main(void)

{

//Создание первого объекта

Printer printer1("HP5P",2004);

printer1.show();

//Создание второго объекта

Printer printer2("Canon_BJC250",2000);

printer2.show();

return 0;

}

Пример 20.10.

Создать программу решения примера 20.7 с использованием конструктора с параметрами.

Полный текст программы для примера 20.10:

//Пример 20.10

#include <iostream.h>

#include <conio.h>

class Printer

{

private:

char model[15]; //модель принтера

int year; //год выпуска

int status; //состояние принтера

public:

//Конструктор с параметрами

Printer(char* _model, int _year);

void init_printer(char* _model, int _year);

void set_print();

void stop_print();

void show();

};

void Printer::init_printer(char* _model,int _year)

{

strcpy(model,_model); //инициализация свойства model

year=_year; //инициализация свойства year

status=0; //начальное состояние - готов к печати

}

void Printer :: set_print()

{

if (!status) status=1;

}

void Printer :: stop_print()

{

status = 0;

}

void Printer :: show()

{

cout<<"Model: "<<model<<" year: "<<year<<" status: "<<status<<endl;

}

Printer :: Printer(char* _model, int _year)//Конструктор с параметрами

{

strcpy(model, _model);

year=_year;

status=0;

}

int main()

{

//Создание первого объекта

Printer printer1("HP5P",2004);

printer1.show();

//Создание второго объекта

Printer printer2("Canon_BJC250",2000);

printer2.show();

cout << "\nНажмите любую клавишу..." ;

getch();

return 0;

}

При выполнении этой программы на экран будет выведено сообщение:

Model: HP5P year: 2004 status: 0

Model: Canon_BJC250 year: 2000 status: 0

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

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

Конструктор всегда существует для любого класса, причем, если он не определен явно, он создается автоматически. По умолчанию создается конструктор без параметров и конструктор копирования. Если конструктор описан явно, то конструктор по умолчанию не создается. По умолчанию конструкторы создаются общедоступными (public).

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

имя_класса имя_объекта (фактические_параметры);

имя_класса (фактические_параметры);

Первая форма допускается только при не пустом списке фактических параметров. Она предусматривает вызов конструктора при определении нового объекта данного класса:

complex ss (5.9,0.15);

Вторая форма вызова приводит к созданию объекта без имени:

complex ss = complex (5.9,0.15);

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

имя_данного (выражение)

Пример 20.11.

class CLASS_A

{

int i; float e; char c;

public:

CLASS_A(int ii,float ee,char cc) : i(8),e( i * ee + ii ),с(сс){}

. . .

};

Пример 20.12.

Класс “символьная строка”.

#include <string.h>

#include <iostream.h>

class string

{

char *ch; // указатель на текстовую строку

int len; // длина текстовой строки

public:

// конструкторы

// создает объект – пустая строка

string(int N = 80): len(0){ch = new char[N+1]; ch[0] = ‘\0’;}

// создает объект по заданной строке

string(const char *arch){len = strlen(arch);

ch = new char[len+1];

strcpy(ch,arch);}

// компоненты-функции

// возвращает ссылку на длину строки

int& len_str(void){return len;}

// возвращает указатель на строку

char *str(void){return ch;}

. . .};

Здесь у класса string два конструктора – перегружаемые функции.

По умолчанию создается также конструктор копирования вида T::T(const T&), где Т – имя класса. Конструктор копирования вызывается всякий раз, когда выполняется копирование объектов, принадлежащих классу. В частности он вызывается:

а) когда объект передается функции по значению;

б) при построении временного объекта как возвращаемого значения функции;

в) при использовании объекта для инициализации другого объекта.

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

string(const string& st)

{len=strlen(st.len);

ch=new char[len+1];

strcpy(ch,st.ch); }

Можно создавать массив объектов, однако при этом соответствующий класс должен иметь конструктор по умолчанию (без параметров).

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

class demo{

int x;

public:

demo(){x=0;}

demo(int i){x=i;}

};

void main(){

class demo a[20]; //вызов конструктора без параметров(по умолчанию)

class demo b[2]={demo(10),demo(100)};//явное присваивание