Класс в ООП

Автор работы: Пользователь скрыл имя, 30 Декабря 2010 в 12:17, реферат

Краткое описание

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

Содержимое работы - 1 файл

OOП.docx

— 37.73 Кб (Скачать файл)

if(y2 >= 0 && y2 <= MAX_SIZE) ep_y = y2;

}  

int sp_x, sp_y;

int ep_x, ep_y;

};  

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

void CPos::SetParam(int x1, int y1, int x2, int y2)

{

if(x1 >= 0 && x1 <= MAX_SIZE) sp_x = x1;

if(y1 >= 0 && y1 <= MAX_SIZE) sp_y = y1;

if(x2 >= 0 && x2 <= MAX_SIZE) ep_x = x2;

if(y2 >= 0 && y2 <= MAX_SIZE) ep_y = y2;

}  

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

class CPos

{

public:

CPos() {} ~

CPos() {}  

void SetParam(int x1, int y1, int x2, int y2);  

int sp_x, sp_y;

int ep_x, ep_y;

};  

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

CPos::CPos()

{

//операторы конструктора 

}  

CPos::~CPos()

{

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

}  

Функцию SetParam() можно вызывать через указатель на класс, используя оператор ‘->’ или через представитель с помощью оператора ‘.’:  

CPos* pos_ptr = new CPos();

CPos pos;  

pos_ptr->SetParam(10,10,20,20);

pos.SetParam(10,10,20,20);  

Таким же образом  можно обращаться и к переменным класса:  

pos_ptr->sp_x = 10;

pos.sp_x = 20;  

Здесь можно заметить, что значения переменных sp_x, sp_y, ep_x и ep_y могут быть заданы как непосредственно при обращении к ним, так и с помощью функции SetParam(). В результате проверка, реализованная в данной функции, может быть проигнорирована программистом. Часто такая ситуация недопустима, например, при использовании готовых классов библиотек MFC, VCL, OWL и др. В связи с этим в классах для переменных и функций предусмотрена возможность установки разных уровней доступа, которые определяются тремя ключевыми словами: public, private и protected.  

Ключевое слово  public означает общий доступ к переменным и функциям класса. Уровень доступа private указывает на частный способ доступа к элементам класса и устанавливается по умолчанию при описании класса. Частный уровень доступа дает возможность обращаться к переменным и функциям только внутри класса и запрещает извне, например, через представители или указатели на класс. Режим доступа protected также как и private запрещает доступ к элементам класса через представители и указатели, но разрешает обращаться к ним из дочерних классов при наследовании.  

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

class CPos

{

public:

CPos() {}

~CPos() {}  

void SetParam(int x1, int y1, int x2, int y2);  

private:

int sp_x, sp_y;

int ep_x, ep_y;

};  

Здесь раздел private ограничивает доступ пользователю класса к переменным sp_x, sp_y, ep_x и ep_y только функцией SetParam(). Следует также отметить, что отсутствие раздела public вначале описания класса привело бы к тому, что все функции класса CPos имели бы область видимости private. В результате доступ к конструктору и деструктору был бы запрещен, и создание нового объекта стало бы невозможным. Аналогичная картина имеет место и в режиме доступа protected, но в отличие от private класс можно использовать как базовый в механизме наследования. Это свойство полезно использовать для запрета создания экземпляров класса, что бывает необходимым, если он является лишь промежуточным звеном в иерархии объектов и не представляет ценности как отдельный объект.

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

Предположим, создается  дочерний класс с именем CLine для работы с линией на основе базового CPos. Для этого после имени дочернего класса CLine ставится символ ‘:’, а затем пишется имя базового класса CPos с указанием уровня доступа:  

class CPos

{

public:

CPos() {}

CPos(int x1, int y1, int x2, int y2) {SetParam(x1,y1,x2,y2);}

~CPos() {}  

void SetParam(int x1, int y1, int x2, int y2);  

protected:

int sp_x, sp_y;

int ep_x, ep_y;

};  

class CLine : public CPos

{

public:

CLine() {}

CLine(int x1,int y1, int x2, int y2) {SetParam(x1,y1,x2,y2);}

~CLine() {}  

void Draw() {MoveTo(sp_x,sp_y); LineTo(ep_x,ep_y);}

};  

В результате наследования с уровнем доступа public класс CLine имеет доступ ко всем переменным и функциям класса CPos, которые не являются частными (private). Ключевое слово public перед именем класса CPos означает, что все общие (public) элементы этого класса остаются с таким же уровнем доступа и в классе CLine. Следует также отметить, что описание класса CPos должно предшествовать описанию класса CLine, а переменные sp_x, sp_y, ep_x и ep_y должны быть описаны в разделе protected для возможности их использования в функции Draw() дочернего класса CLine и в то же время не доступными извне.  

Класс CLine содержит два конструктора, деструктор и функцию Draw() для рисования линии на экране. При этом процедура задания координат графического объекта целиком находится в базовом классе CPos и по мере необходимости используется в дочернем классе CLine. Такое разделение оказывается удобным, т.к. при описании работы с новыми графическими объектами процедура работы с их координатами будет оставаться одной и той же и находится в одном классе. Если бы в данном случае использовался структурный подход к программированию, то алгоритм работы с координатами графических примитивов пришлось бы прописывать каждый раз для всех типов объектов, что привело бы к заметному усложнению текста программы.  

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

CLine* line_ptr = new CLine();  

или  

CLine line;  

При создании нового объекта CLine вызывается сначала конструктор CPos() базового класса, а затем конструктор дочернего – CLine(). Таким образом, создается как бы два объекта: CPos и CLine, но они представляются как единое целое объекта CLine.  

В представленном классе CLine предусмотрено два конструктора: с параметрами и без них. В случае вызова конструктора с параметрами  

CLine line(10,10,20,20);  

вызывается конструктор  CPos() базового класса, а затем конструктор CLine(int x1, int y1, int x2, int y2) дочернего, в котором выполняется функция SetParam() для записи значений координат графического объекта.  

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

class CLine : public CPos

{

public:

CLine() : CPos()

{

}

CLine(int x1,int y1, int x2, int y2) : CPos(x1,y1,x2,y2)

{

}

~CLine() {}  

void Draw() {MoveTo(sp_x,sp_y); LineTo(ep_x,ep_y);}

};  

В приведенном примере  конструктор CLine() будет вызывать конструктор CPos() базового класса, а конструктор CLine(int x1, int y1, int x2, int y2) конструктор CPos(int x1, int y1, int x2, int y2). При этом функция SetParam() в CLine(int x1, int y1, int x2, int y2) может быть опущена, т.к. необходимая инициализация переменных будет выполнена при вызове конструктора CPos(int x1, int y1, int x2, int y2) базового класса.  

В рассматриваемой  задаче программирования графического редактора, класс CPos является вспомогательным, т.е. он служит для создания описания новых классов как базовый. При этом нет необходимости создавать его экземпляр в памяти ЭВМ для непосредственной работы с ним. Поэтому целесообразно защитить его от возможности создания путем помещения конструкторов данного класса в раздел protected. Такие классы называются абстрактными, т.е. они не могут существовать как самостоятельные объекты, а служат для создания новых, дочерних классов. Описание абстактного класса CPos и дочернего от него CLine показано ниже:  

class CPos

{

protected:

CPos() {}

CPos(int x1, int y1, int x2, int y2) {SetParam(x1,y1,x2,y2);}

~CPos() {}  

public:

void SetParam(int x1, int y1, int x2, int y2);  

protected:

int sp_x, sp_y;

int ep_x, ep_y;

};  

Функции классов  CPos и CLine можно вызывать, например, через представитель класса CLine, следующим образом:  

CLine line;

line.SetParam(10,10,20,20);

line.Draw();  

Обратите внимание, что благодаря полиморфизму, функция  SetParam(), заданная в классе CPos, вызывается через представитель line как будто она определена в классе CLine. В результате, единожды объявленная функция SetParam() может быть многократно использована в разных классах, производных от CPos.  

Для работы с другими  графическими примитивами (прямоугольником  и эллипсом) подобным образом можно  создать дочерние классы от CPos, отличающихся друг от друга реализацией функции Draw():  

class CRect : public CPos

{

public:

CRect() : CPos()

{

}

CRect(int x1,int y1, int x2, int y2) : CPos(x1,y1,x2,y2)

{

}

~CRect() {}  

void Draw() {Rectangle(sp_x,sp_y,ep_x,ep_y);}

};  

class CEllipse : public CPos

{

public:

CEllipse() : CPos()

{

}

CEllipse(int x1,int y1, int x2, int y2) : CPos(x1,y1,x2,y2)

{

}

~CEllipse() {}  

void Draw() {Ellipse(sp_x,sp_y,ep_x,ep_y);}

};  

В результате построения объектов получается следующая иерархия (рис. 6.1).  

  

Рис. 6.1. Иерархия классов  графических примитивов  

У каждого из представленных дочерних объектов CLine, CRect и CEllipse имеется один базовый объект CPos. Вместе с тем язык С++ предоставляет возможность создавать дочерние объекты на основе нескольких базовых, что приводит к концепции множественного наследования.  

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

class CProp

{

protected:

CProp() {}

CProp(int wdt, int clr) {SetProperty(wdt,clr);}

~CProp();  

public:

void SetProperty(int wdt, int clr)

{

if(wdt >= 0 && wdt <= MAX_WIDTH) width = wdt;

if(clr >= 0 && clr <= MAX_COLOR) color = clr;

}

protected:

int width, color;

};  

Информация о работе Класс в ООП