Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Lab11

.pdf
Скачиваний:
8
Добавлен:
23.03.2015
Размер:
311.18 Кб
Скачать

1

Лабораторнаяработа№2.

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

C++.

2.1. Определениекласса...............................................................................

1

2.2. Созданиеэкземпляракласса..................................................................

2

2.3. Доступкчленамкласса........................................................................

3

2.4. Инкапсуляция........................................................................................

5

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

7

2.6. Перегруженныеконструкторы............................................................

9

2.7. Инициализацияпеременных-членоввконструкторах......................

10

Задания......................................................................................................

12

В этой лабораторной работе рассматриваются классы языка C++. При определении класса создается новый тип данных, который можно использовать подобно встроенному типу данных C++. Однако, в отличие от встроенных типов, классы содержат как данные, так и функции. Класс позволяет инкапсулировать все функции и данные, необходимые для управления частными компонентами программы (например, окном на экране; рисунком, построенным с помощью графической программы; устройством, подключенным к компьютеру; задачей, выполняемой операционной системой). Рассматриваются базовые средства создания и использованияотдельныхклассов.

2.1. Определениекласса.

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

Структуры языка С позволяют сгруппировать набор связанных переменных-членов. Например, если создан прямоугольник, удобно сохранить его координаты в виде структуры, определенной следующим образом.

struct Rectangle { int Left;

int Top;

int Right; int Bottom; };

Далее можно определить функцию рисования прямоугольника.

void

DrawRectangle

(struct Rectangle *Rect)

{

(Rect->Left,

Rect->Top,

Rect->Right,

Line

Rect->Top) ;

Rect->Top,

Rect->Right,

Line

(Rect->Right,

2

Rect->Bottom) ;

Line (Rect->Right, Rect->Bottom, Rect->Left, Rect->Bottom) ;

Line (Rect->Left, Rect->Bottom, Rect->Left, Rect->Top) ;

}

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

Наконец, чтобы задать прямоугольник в определенном месте, нужно определить и инициализировать переменную типа Rectangle, а затем передать ее в функцию DrawRectangle.

struct Rectangle Rect = (25, 25, 100, 100); DrawRectangle (&Rect);

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

class CRectangle {

int Left; int Top; int Right; int Bottom; void Draw (void) {

Line (Left, Top, Right, Top) ; Line (Right, Top, Right, Bottom) ;

Line (Right, Bottom, Left, Bottom) ;

Line (Left, Bottom, Left, Top) ;};

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

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

Функции, определенные внутри класса, называются функциями-членами или методами класса. В этом примере переменные-члены — Left, Top, Right и Bottom, а функция-член - Draw. Обратите внимание: функция-член может содержать ссылку на любую переменную класса, не используя при этомспециальныйсинтаксис.

2.2. Созданиеэкземпляракласса.

В языке С следующее определение структуры передает компилятору сообщение о ее форме, но не резервирует место в памяти и не создает переменную, которую можно использовать для хранения данных.

struct Rectangle { int Left;

int Top; int Right;

int Bottom; };

3

Чтобызарезервироватьпамятьисоздатьпеременную, нужнозадать определение

struct Rectangle Rect;

Аналогично определяется класс, например CRectangle, показанный в предыдущем параграфе. При этом компилятору предоставляется проект класса, но в действительности место в памяти не резервируется. Как и структура, такая переменная-член должна определяться выражением типа

CRectangle Rect;

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

Примечание Точно так же, как и для структур языка С, определение класса должно

предшествовать определению и использованию экземпляра класса в исходном файле.

Экземпляр класса можно создать, используя имеющийся в языке C++ оператор new, например:

CRectangle *PRect = new CRectangle;

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

delete Rectangle;

Можно создать произвольное число экземпляров данного класса.

Совет При создании экземпляра класса перед именем класса можно не

указывать слово class. В C++ определение класса создает новый тип данных, на который можно сослаться, используя одно лишь имя класса.

2.3. Доступкчленамкласса.

После создания экземпляра класса организуется доступ к переменным-членам и функциям-членам класса. При этом используется синтаксис, подобный применяемому для работы со структурами языка С. Однако при наличии одного только определения класса Rectangle программа не сможет обратится ни к одному из его членов, так как по умолчанию все переменные и функции, принадлежащие классу, определены как закрытые (private) (иногда говорят внутренние, личные или частные). Это означает, что они могут использоваться только внутри функций-членов самого класса. Так, для функции Draw разрешен доступ к переменным-членам Top, Left, Right и Bottom, потому что Draw — функция-член класса. Для других частей

4

программы, таких как функция main, доступ к переменным-членам или вызов функции-члена Draw запрещен.

К счастью, можно использовать спецификатор доступа public, чтобы создать открытый член класса (иногда называемый общедоступным или публичным), доступный для использования всеми функциями программы (как внутри класса, так и за его пределами). Например, в следующем варианте класса Rectangle все члены являются открытыми.

class CRectangle

(

public: int Left; int Top; int Right; int Bottom;

void Draw (void)

{

Line (Left, Top, Right, Top) ; Line (Right, Top, Right, Bottom) ;

Line (Right, Bottom, Left, Bottom) ;

Line (Left, Bottom, Left, Top) ;};

Спецификатор доступа применяется ко всем членам, расположенным после него в определении класса (пока не встретится другой спецификатор доступа, как будет показано ниже).

Теперь, когда все члены класса CRectangle открыты, доступ к ним, как и доступ к полям структуры в языке С, возможен с использованием оператора "."

CRectangle Rect; // определение объекта

CRectangle

Rect.Left = 5;// присваивание значений переменнымчленам

Rect, Top =10;// для указания координат прямоугольника

Rect. Right = 100;

Rect. Bottom = 150;

Rect. Draw ( ) ; // создание прямоугольника

С другой стороны, можно создать экземпляр класса оператором new, а затем использовать указатель на экземпляр для доступа к переменнымчленам класса, как показано в следующем коде.

CRectangle *PRect = new CRectangle; PRect->Left = 5;

PRect->Top = 10; PRect->Right = 100; PRect->Bottom = 150;

PRect->Draw ();

5

2.4. Инкапсуляция.

Согласно принципам инкапсуляции внутренние структуры данных, используемые в реализации класса, не должны быть доступны пользователю класса непосредственно (преимущества инкапсуляции будут рассмотрены ниже). Однако текущая версия класса Rectangle явно нарушает этот принцип, так как пользователь может непосредственно читать или модифицировать любые переменныечлены.

Для достижения большей инкапсуляции класс CRectangle должен быть определен так, чтобы иметь доступ к функциям-членам (в нашем случае к Draw), но не иметь доступа к внутренним переменным-членам, используемым этими функциями (Left, Top, Right и Bottom).

class CRectangle

{

private: int Left; int Top; int Right; int Bottom; public:

void

Draw (void)

{

(Left, Top, Right, Top) ;

Line

Line

(Right, Top, Right, Bottom) ;

Line

(Right, Bottom, Left, Bottom) ;

Line

(Left, Bottom, Left, Top) ;}};

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

Left, Top, Right и Bottom закрытыми, а функцию Draw открытой.

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

Примечание

Язык C++ предоставляет еще и третий вид доступа - protected. Этот спецификатор будет рассмотрен в позже, поскольку требует понимания термина "наследование".

Следующий код иллюстрирует как корректное, так и некорректное обращение к членам очередного варианта класса Rectangle.

void main ()

{CRectangle Rect;// определение объекта CRectangle

6

Rect.Left = 5;// ОШИБКА: нет доступа к закрытому //члену

Rect.Top = 10; // ОШИБКА Rect.Right = 100; // ОШИБКА Rect.Bottom = 150; // ОШИБКА

Rect.Draw();//допускается (но координаты не //определены)}

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

void

SetCoord

(int

L,

int

T,

int R,

int

B)

(

max

(0,L),

80);

 

{L =

min

25);

T =

 

min

(

max

(0,T),

R =

 

min

(

max

(0,R),

80);

В =

 

min

(

max

(0,B),

25);

R =

max

max

(R, L) ;

 

 

 

В =

(B,T);

 

Right = R;

Bottom =

Left

= L;

Top = T;

B;}};

Эта функция добавляется в раздел public определения класса Rectangle.Поэтому ее можно вызвать из любой функции программы. Обратите внимание:при необходимости, перед присваиванием параметров переменным класса, функция SetCoord организует проверку нахождения параметров в диапазоне корректных значений и следит, чтобы правая координата была больше левой, а нижняя — больше верхней. Макросы max и min предоставляются динамической библиотекой языка C++. Для их применения в программу нужно включитьфайл заголовков stdlib.h.

Теперь класс CRectangle можно использовать для создания прямоугольника.

void main () {CRectangle Rect;

Rect.SetCoord(25,25,100,100);//установка координат

//прямоугольника

Rect.Draw ();// отображение прямоугольника

}

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

void GetCoord (int L, int Т, int R, int B)

7

{

*L = Left;

*T = Top;

*R = Right;

*B = Bottom; }

Эта функция также должна быть добавлена в раздел public определения класса. Ниже приведено законченное определение класса Rectangle, содержащее новые функции-члены SetCoord и GetCoord.

#include <stdlib.h>

class Rectangle

{

 

private:

int Left;

int Top;

int Right;

int Bottom;

public:

void Draw (void) {

Line

(Left, Top, Right, Top);

Line

(Right, Top, Right, Bottom);

Line

(Right, Bottom, Left, Bottom);

Line

(Left, Bottom, Left, Top);

}

 

void

GetCoord (int *L, int *T, int *R, int *B) {

*L =

Left; *T = Top; *R = Right; *B = Bottom;}

void

SetCoord (int L, int T, int R, int B){

L =

min

(

max

(0,L),

80);

25);

T =

 

min

(

max

(0,T),

R =

 

min

(

max

(0,R),

80);

В =

 

min

(

max

(0,B),

25);

R =

max

max

(R, L) ;

 

 

 

В =

(B,T);

 

 

 

 

Left

= L; Top = T; Right = R; Bottom = B;}};

Теперь, с помощью функций-членов SetCoord и GetCoord класс Rectangle предоставляет доступ к закрытым переменным (согласно принципам инкапсуляции) только посредством четко определенного интерфейса, контролирующего корректность новых присвоенных значений и, при необходимости, корректирующего эти значения.

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

Предыдущий вариант класса CRectangle позволяет

8

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

Конструктор имеет такое же имя, как и класс. При определении конструктора нельзя указывать тип возвращаемого значения, даже void (конструктор никогда не возвращает значение). Однако он может принять любое число аргументов (включая нулевое). Например, следующий вариант класса CRectangle содержит конструктор, принимающий четыре параметра для инициализации переменных-членов. (Вспомните: функция-член SetCoord проверяет корректность значений аргументов и присваивает значения параметров закрытым переменным-членам, хранящим координаты прямоугольника.)

class CRectangle {

private: int Left; int Top; int Right; int Bottom; public:

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

CRectangle (int L, int T, int R, int Б)

{

SetCoord (L, T, R, B) ;

}

// определения других функций-членов ...

};

Примечание Для создания экземпляра класса необходимо, чтобы конструктор был функцией-

членом типа public.

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

CRectangle Rect (25,25,100,100);

Такое определение создает экземпляр класса CRectangle, вызывая конструктор класса и передавая ему заданные значения параметров.

При создании экземпляра класса значения параметров можно передать конструктору, используя оператор new.

CRectangle *PRect = new CRectangle (25,25,100,100);

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

Имея конструктор, можно создать объект Rectangle и нарисовать прямоугольник с помощью двух операторов (а не трех, как в параграфе "Инкапсуляция").

void main ( )

9

{CRectangle Rect (25,25,100,100); //создание объекта и описание размеров //прямоугольника

Rect.Draw();

// рисование прямоугольника

}

 

Конструктор без параметров называют конструктором по умолчанию. Такой конструктор обычно инициализирует переменные-члены, присваивая им стандартные, установленные по умолчанию значения. Например, следующий вариант класса CRectangle имеет конструктор по умолчанию, инициализирующий все данные значениями 0.

class CRectangle

{

private:

int Left; int Top; int Right; int Bottom; public:

CRectangle ()

{Left = Top = Right = Bottom = 0; }

// определения других функций-членов ...

};

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

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

CRectangle Rect;

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

CRectangle Rect

(); // определение функции, которая

не

//принимает параметры и возвращает

//объект CRectangle

Если допустить такую ошибку, компилятор не сгенерирует сообщение об ошибке до тех пор, пока вы не попытаетесь использовать Rect как экземпляр класса.

2.6. Перегруженныеконструкторы.

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

10

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

class CRectangle

{

private: int Left; int Top; int Right; int Bottom; public:

//конструктор по умолчанию: CRectangle ()

{

Left = Top = Right = Bottom = 0;

}

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

CRectangle (int L, int T, int R, int 8)

{

SetCoord (L, T, R, B);

}

// определения других функций-членов ... };

Следующий код демонстрирует использование перегруженного конструктора CRectangle.

void main()

{

//создание объекта с использованием конструктора по умолчанию: CRectangle Rectl;

//создание объекта с указанием начальных значений: CRectangle Rect2 (25, 25, 100, 100) ;

Примечание При определении конструктора класса компилятор не создает конструктор по

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

2.7. Инициализацияпеременных-членоввконструкторах.

При определении класса запрещается инициализировать переменные-члены. Так, следующее определение класса содержит ошибки.

class С

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]