Автор работы: Пользователь скрыл имя, 30 Декабря 2010 в 12:17, реферат
Класс в ООП - это абстрактный тип данных, который включает в себя не только данные, но и функции и процедуры.
Функции и процедуры класса называются методами и содержат исходный код, предназначенный для обработки внутренних данных объекта данного класса.
if(y2 >= 0 && y2 <= MAX_SIZE) ep_y = y2;
}
int sp_x, sp_y;
int ep_x, ep_y;
};
В приведенном примере
реализована функция SetParam()
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_
};
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;
};