Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка по программированию.doc
Скачиваний:
11
Добавлен:
13.11.2019
Размер:
1.2 Mб
Скачать

Void main()

{

PROB cl1;

cl1.FuncIn(3);

cl1.FuncOut();

}

Обращаем внимание на то, что необходимо сделать подключение заголовочного файла Unit2.h с помощью директивы include.

Что же происходит при запуске программы? В первой строке создается объект класса. Назван он cl1. Во второй строке вызывается метод FuncIn с аргументом, равным 3. Как можно видеть, при вызове метода сначала указывается имя объекта и затем, после разделителя . имя функции. В результате свойство iii становится рамным 3. Наконец функция FuncOut произведет вывод значения этого самого свойства на экран.

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

Применительно к классу, описанному выше, может понадобиться, например, начальное обнуление переменной iii. В заголовочном файле Unit2.h в описании класса теперь поместим строку:

PROB();

В файле реализации Unit2.cpp опишем конструктор:

PROB::PROB()

{iii = 0.0;}

Теперь в вызывающем модуле Unit1.cpp при создании объекта в строке:

PROB cl1;

сразу произойдет присвоение значения 0 свойству iii.

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

PROB(int);

PROB::PROB(int x)

{iii = x;}

PROB cl2(5);

Понятно, что теперь необходимость в методе FuncIn отпала.

Из представленных ниже текстов файлов Unit2.h, Unit2.cpp и Unit1.cpp будет понятен синтаксис использования рассматриваемых конструкторов и операторов.

//----------------------Unit2.h

class PROB

{

int iii;

public:

Void FuncOut();

PROB();

PROB(int);

}

//----------------------Unit2.cpp

#include "Unit2.h

#include<conio.h>

#include<stdio.h>

Void prob::FuncOut()

{

printf("%d",iii);

getch();

}

PROB::PROB(int x)

{ iii=x; }

PROB::PROB()

{iii = 0;}

//---------------------- Unit1.cpp

#include "Unit2.h"

Void main()

{

PROB cl1,cl2(5);

cl1.FuncOut();

cl2.FuncOut();

}

Итак, в первой строке вызывающей программы создается объект cl1 класса PROB с использованием конструктора без параметров и объект cl2 с использованием инициализирующего конструктора с параметром.. При этом обнуляется свойство iii объекта cl1, а переменная-член iii в cl2 получает значение 5. Далее свойства объектов выводятся на экран.

Удаление объекта класса также сопровождается выполнением специального метода, называемого деструктором. Вызов деструктора в явном виде в приложении не делается. Он производится автоматически либо при выходе из блока (для локальных объектов) либо при завершении приложения (для глобальных объектов). Сразу отметим, что деструкторы, как и конструкторы, не обязательно и явно декларировать – всегда, когда необходимо, будут срабатывать конструкторы и деструкторы по умолчанию. Однако, если при удалении объекта необходимо выполнить какие-то действия, то «самодельный» деструктора может быть полезным. Имя функции-деструктора совпадает с именем класса, перед которым пишется символ ~ (тильда). Этот метод не имеет типа и не возвращает никакого значения.

Для демонстрации работы деструктора добавим в файл Unit2.h строку:

~PROB();

В файле реализации дадим описание метода:

PROB::~PROB()

{ printf("FINISH"); }

Как нетрудно догадаться, выполнение деструктора заключается в выводе сообщения FINISH. Больше ничего в программе делать не надо. По окончанию работы приложения вы увидите на экране это самое сообщение.

Перегрузка функций и операторов

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

Начнем с перегруженных функций. Классическим примером здесь служит функция, вычисляющая модуль (абсолютную величину) числа. Стандартной функцией в С/С++ для нахождения модуля целого числа является функция int abs(int). Подчеркнем, что аргументом функции должно быть целое число, а возвращаемое число также целого типа. Применительно к вещественным числам то же действие выполняет функция float fabs(float). Логично было бы попробовать «научить» функцию abs работать с любыми аргументами – целыми, вещественными, комплексными и возвращать значения соответствующих типов. При этом имя функции одно для всех типов. Вот в этом и состоит смысл перегрузки функции. Как это делается практически?

Если бы мы решили создать собственную функцию abs, возвращающую модуль целого (типа int) числа, то это можно было бы сделать, например, так, как показано в следующем фрагменте:

int abs(int x)

{

int y;

if(x<0) y = -x; else y=x;

return y;

}