double arrow

Initgraph( тип графического драйвера, режим адаптера , путь к драйверу)

DB DA

Void main ()

{ B b (5);

cout<<endl<< “ b =” << b.GetY ();

cout<<endl<< “ a =” << b.GetX ();

}

В производный класс B включаются все данные и функции родителя А, при этом данное x - недоступно для прямого обращения из объектов класса B, но к нему можно обращаться из доступных компонентных функций класса А, которые стали полноправными членами класса B: b.GetX ();

Таким образом, через открытую функцию класса A GetX() мы получаем доступ к закрытому данному этого класса (x), а функция GetY () класса B предоставила доступ к закрытому данному (y) производного класса.

В main создается объект производного класса B, компонентному данному которого передается значение 5.

Данное класса А инициируется значением 0.

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

В нашем случае сначала вызывается конструктор A (), который по умолчанию инициирует x значением 0, а затем вызывается B(5), инициирующий y значением 5.

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

Результат программы:

A! B!

b= 5

a= 0

Наличие производного класса не запрещает создавать отдельно объекты базового класса, например:

A a (7);

Передача параметров в базовый класс

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

Для этого в конструкторе производного класса надо явно вызвать конструктор базового класса.

Рассмотрим этот вопрос на примере:

class A { int x1, x2;

public:

A (int ax1, int ax2) { x1 = ax1; x2 = ax2; }

};

class B: public A {

int y;

public:

B (int _x1, int _x2, int _ y): A (_x1, _x2) { y = _ y; }

};

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

- После “: ” производится вызов конструктора базового класса с перечисленными выше параметрами для базового класса (естественно, вызов – без указания типов)

- При вызове конструктора производного класса B (), ему необходимо передать три параметра, два из которых будут переданы конструктору базового класса A ().

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

B b (2, 3, 4); значения 2 и 3 будут переданы в переменные x1 и x2

а значение 4 – в переменную y.

Для правильного построения конструктора производного класса необходимо иметь описание конструктора базового класса!

Конструкторы с инициализацией по умолчанию в иерархии классов

Рассмотрим в качестве примера конструктор производного класса с инициализацией по умолчанию.

class A { // базовый класс

int x1, x2; //закрытые данные

public: //открытые функции

(1) A(int ax1, int ax2) { x1= ax1; x2 = ax2;} //конструктор с параметрами

int GetX1 () { return x1;}

int GetX2 () { return x2;}

};

class B: public A { // производный класс

int y;

public:

// конструктор с умалчиваемыми значениями

(2) B (int ax1 =1, int ax2 = 2, int y1 = 3): A (ax1, ax2) { y = y1}

int GetY () { return y;}

};

void main ()

{ B b1 (10, 20, 30);

cout<<endl<< b1.GetX1 () << “ “ <<b1.GetX2 () <<” “ << b1.GetY ();

// 10 20 30

B b2 (10, 20);

cout<<endl<< b2.GetX1 () << “ “ <<b2.GetX2 () <<” “ << b2.GetY ();

//10 20 3

B b3 (10);

cout<<endl<< b3.GetX1 () << “ “ <<b3.GetX2 () <<” “ << b3.GetY ();

//10 2 3

B b4;

cout<<endl<< b4.GetX1 () << “ “ <<b4.GetX2 () <<” “ << b4.GetY ();

//1 2 3

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

A a (40, 50);

В производном классе B конструктор имеет параметры по умолчанию для всех переменных и производного и базового класса. Это позволяет создавать объекты производного класса, передавая им разное количество параметров.

Если бы конструктор базового класса имел параметры по умолчанию, то эти значения могли бы реализовываться только в объектах базового класса:

(3) A(int ax1=3, int ax2=5) { x1= ax1; x2 = ax2;}

A a;

cout<<endl<< a.GetX1 () << “ “ <<a.GetX2 () // 3 5

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

Возможны следующие типы конструкции классов:

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

class B: public A {

int y;

public:

B (int y1=0) { y = y1; } };

При создании объекта класса В:

В b (5);

значение 5 присвоится y, а переменные класса А получат значения по умолчанию из конструктора (3).

- Если в производном классе В отсутствуют собственные данные, и нас устраивают значения по умолчанию класса А, то конструктор в классе В вообще не нужен, при создании объекта производного класса:

B b;

в объекте b данные базового класса A инициированы значениями по умолчанию из конструктора базового класса (3).

- Если в производном классе нет своих данных, но при создании объектов

производного класса нас не устраивают значения по умолчанию из конструктора базового класса. Тогда в конструкторе класса В нужно вызвать конструктор А, чтобы передать ему нужные аргументы:

class B: public A {

public:

B (int ax1, int ax2): A (ax1, ax2) { }

};

При создании объекта производного класса:

B b (15,20);

передаваемые параметры инициализируют данные базового класса.

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

B(int ax1): A(ax1) { } …

B n (37); // в создаваемом объекте 37 присвоится x1, а x2 будет иметь

// значение поумолчанию 5

Или не всем данным в конструкторе базового класса даны умалчиваемые значения:

A (int ax1, int ax2 =0) {x1 =ax1; x2 = ax2; }

B (int ax1): A (ax1) { }

B b (11) // x1 присвоится 11, а x2 инициируется 0.

и т. д.

Класс “точка на графическом экране”. Производный класс –“пятно”

// следующее описание класса point находится в модуле point.h

#ifndef PH

#define PH 1

class point { // точка на экране дисплея

protected:

int x, y; // защищенные компонентные данные

public: // общедоступные компонентные функции

point (int xx=0, int yy =0); // прототип конструктора

// с умалчиваемыми значениями

int& GetX (); // функция возвращает координату x

int& GetY (); // функция возвращает координату y

void show (void); // прототип функции изображения точки

void move (int xo=0, int yo =0); // прототип функции

// перемещения точки с умалчиваемыми значениями

// по умолчанию перемещает в нулевые координаты

private: // собственная функция класса

void hide (); // прототип функции, убирающей точку с экрана

};

#endif

// внешнее определение методам класса находится в модуле point.cpp

#ifndef PC

#define PC 1

# include <graphics.h> // подключение графической библиотеки

# include “point.h” //необходимо включить описание класса point

point::point(int x1, int y1) // определение конструктора

{ x = x1; y = y1; }

void point:: show (void)

{

putpixel (x, y, getcolor());

// изображает точку с координатами x, y цветом,

// номер которого дает третий параметр

// int getcolor(void) - возвращает текущий номер цвета символов

}

void point:: hide(void) // убирает точку с экрана

{ putpixel (x, y, getbkcolor()); } // int getbkcolor(void) -

// возвращает номер цвета фона

void point::move (int xn, int yn)

{ hide (); // убирает тоску с координатами x, y

x =xn; y= yn; // координатам присваивается новое значение

show (); // изображается точка с новыми координатами

}

int&point::GetX (){return x;}

int& point:: GetY(void) {return y;}

#endif

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

Все эти функции предоставляют возможности управления графическим экраном.

Стандартное состояние ПК – соответствует работе экрана в текстовом режиме (25 строк по 80 символов в строке).

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

Для управления техническими средствами ПК имеются соответствующие программы, называемые драйверами.

Графический драйвер управляет дисплейным адаптером в графическом режиме.

Графические возможности адаптера определяются разрешением экрана (количеством точек экрана) и количеством цветов, которыми может светиться каждая точка.

Наиболее распространенные дисплейные адаптеры (CGA - Color Graphics Adapter, EGA – Enhanced (усиленный) Graphics Adapter, VGA – Video Graphics Array (графический видеомассив), SVGA и т. д.) могут иметь несколько графических режимов работы. Для управления современными графическими адаптерами мы используем драйвер EGAVGA.BGI

Экран представляет собой совокупность светящихся точек - пикселей. Количество точек определяется монитором и режимом драйвера для работы с ним. Положение пикселя определяется его координатами по отношению к точке с координатами 0, 0 – верхнему левому углу экрана.

Для инициализации графического режима адаптера используется вызов функции:

void far initgraph (int far * graphdriver, int far * graphmode, char far * pathtodriver);

Для указания типа драйвера в файле имеются константы:

DETECT = 0 (режим автоопределения типа)

CGA =1

EGA=3

VGA=9

и т. д.

Аналогично имеются константы для определения моды адаптера.

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

int dr = DETECT, // тип драйвера и

mod; // режим работы адаптера

// определяются автоматически

//режим при этом выбирается с максимальным разрешением

initgraph (&dr, &mod, "D:\\Borlandc\\BGI");

// предполагается, что драйвер находится в каталоге BGI

/* #include<conio.h>

#include “point.h”

#include ”point.cpp”


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



Сейчас читают про: