Объектно-ориентированное программирование на C++


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


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

struct Point

{

int X;

int Y;

};

Но пиксел на экране монитора, кроме координат своего положения, обладает еще и возможностью "светиться". Расширим структуру:

enum Boolean {false, true}; // false = 0, true = 1

struct Point

{

int X;

 int Y;

 Boolean Visible;



};

Тип Boolean хорошо знаком программистам на Паскале. Этот код использует перечисляемый тип enum для проверки true (истина) или false (ложь). Так как значения перечисляемого типа начинаются с 0, то Boolean может иметь одно из двух значений: 0 или 1 (ложь или истина).

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

enum Boolean {false, true}; // false = 0, true = 1

class Point

{

protected:

 int X;

 int Y;

 Boolean Visible;

public:

 int GetX(void) { return X; }

 int GetY(void) { return Y; }

 Boolean isVisible (){ return Visible;}

 Point (const Point& cp); // прототип конструктора копирования

 Point (int newX =0, int new Y =0); // прототип конструктора

};

Point :: Point (int NewX, int NewY) // конструктор

{

 X = newX; Y = newY; Visible = false;

}

Point :: Point (const Point& cp) // конструктор копирования

{

 X = cp.X; Y = cp.Y; Visible = cp.Visible;

}

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

Point Center(320, 120); // объект Center типа Point

Point *point_ptr; // указатель на тип Point

point_ptr = &Center; // указатель показывает на Center


Задание аргументов по умолчанию при описании прототипа конструктора дает нам возможность вызывать конструктор без аргументов или с неполным списком аргументов:
Point aPoint ();

Point Row[80]; // массив из объектов типа Point

Point bPoint (100);
Пока мы может создавать объекты класса Point и определять их координаты, но не можем пока их показывать. Так что необходимо дополнить класс Point соответствующими методами.
class Point

{

 ...

public:

 ...

 void Show();

 void Hide();

 void MoveTo(int newX, int newY);

};
void Point::Show()

{

 Visible = true;

 putpixel (X,Y,getcolor());

}
void Point::Hide()

{

 Visible = false;

 putpixel (X,Y,getbkcolor());

}
void Point::MoveTo (int newX, int newY)

{

 Hide ();

 X = newX;

 Y = newY;

 Show ();

}
Теперь, когда у нас есть полноценный класс Point, можно создавать объекты-точки, высвечивать, гасить и перемещать их по экрану.
Point pointA (50,50);

pointA.Show ();

pointA.MoveTo (100,130);

pointA.Hide ();
Если потребуется создать класс для другого графического объекта, то можно выбрать один из двух способов: либо начать его реализацию "с нуля", либо воспользоваться уже готовым классом Point, сделав его базовым. Второй способ кажется более предпочтительным, поскольку он предполагает использование уже готовых модулей, все, что при этом нужно - это создать новый производный от Point класс, дополнив его новыми состояниями и методами и/или переопределив некоторые методы базового класса.
Давайте попробуем создать класс Circle для окружности. Окружность, в известном смысле, является жирной точкой. Она имеет все, что имеет точка (позицию X и Y и видимое/невидимое состояние) плюс радиус. По-видимому, класс Circle появляется, чтобы иметь только отдельный элемент Radius, однако не забывайте обо всех элементах, которые наследует Circle, являясь классом, порожденным из Point. Circle имеет X, Y, а также Visible, даже если их не видно в определении класса для Circle.


class Circle: public Point

{

 int Radius; // private по умолчанию

public:

 Circle ( int initX, int initY, int initR);

 void Show ();

 void Hide ();

 void Expand (int deltaR);

 void Contract (int deltaR);

 void MoveTo (int newX, int newY);

};
Circle::Circle (int initX, int initY, int initR) // конструктор

 :Point (initX, initY) // вызов конструктора базового класса

{

 Radius = initR;

}
void Circle::Show ()

{

Visible = true;

circle (X,Y, Radius);

}
void Circle::Hide () // скрыть = зарисовать цветом фона

{

 Visible = false;

 unsigned int tempColor = getcolor ();

 setcolor (getbkcolor());

 circle (X,Y, Radius);

 setcolor (tempColor);

}
void Circle::Expand (int deltaR)

{

 Hide();

 Radius += deltaR;

 Show();

}
void Circle::Contract (int deltaR)

{

 Expand (-deltaR);

}
void Circle::MoveTo (int newX, int newY)

{

 Hide ();

 X = newX;

 Y = newY;

 Show ();

}
main()

{

 int graphDr = DETECT, graphMode;

 initgraph ( &graphDr, &graphMode, "");

 

 Circle C (150,200,50); // создать объект окружность с центром в т.(150, 200) и радиуса 50

 C.Show(); // показать окружность

 getch();

 C.MoveTo (300,100); // переместить

 getch();

 C.Expand (50); // растянуть

 getch();

 C.Contract (70); // сжать

 getch();

 

 closegraph();

}
Поскольку класс Circle - производный от класса Point, то, соответственно, класс Circle наследует из класса Point состояния X, Y, Visible, а также методы isVisible(), GetX(), GetY(). Что касается методов Show(), Hide() и MoveTo() класса Circle, то необходимость их переопределения продиктована спецификой объектов нового класса, поскольку, например, показать окружность, - это не то же самое, что показать точку.
Заметьте, что методы Circle требуют доступа к различным элементам данных в классах Circle и Point. Рассмотрим Circle::Expand. Она требует доступа к Radius. Нет проблем. Radius определен как private в самом Circle. Поэтому Radius доступен любой функции элементов из класса Circle.
Теперь рассмотрим Circle::Hide и Circle::Show. Они требуют доступа к Visible из своего базового класса Point. В этом примере Visible имела protected доступ в Point. А Circle порождается с доступом public из Point. Поэтому, Visible имеет protected доступ в пределах Circle. Заметим, что если бы Visible определялась как private в Point, то она была бы недоступна для функций элементов Circle. Можно было бы сделать Visible c доступом public. Однако в таком случае Visible сделалась бы доступной для функций не являющихся элементами.

Содержание раздела