Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
posobie1.doc
Скачиваний:
13
Добавлен:
01.05.2019
Размер:
457.22 Кб
Скачать

4.4. Виртуальные классы

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

//Листинг 27. Определение классов «шахматные фигуры»

class Figure //класс «фигура»

{ protected:

int hor; //позиция фигуры по горизонтали

char vert; //позиция фигуры по вертикали

int color; //цвет фигуры

public:

Figure(char x, int y, int z) //конструктор

: vert(x), hor(y), color(z)

{}

};

class Castle : public Figure //класс ладья

{ public:

Сastle(char x, int y, int z):

Figure (x, y, z) //конструктор

{}

int Move(char x, int y) //функция, реализующая ход ладьи на поле [x y ]

{ if ( ((x == vert)

&& (y != hor))

|| ((x != vert)

&& (y == hor)))

{

hor = y;

vert = x;

return 1;

}

return 0;

}

};

class Bishop : public Figure //класс слон

{ public:

Bishop(char x, int y, int z):

Figure (x, y, z) //конструктор

{}

int Move(char x, int y) //функция, реализующая ход слона на поле [x y ]

{ if (abs((x - vert)

== abs(y - hor))

&& (x != vert)) {

vert= x; y=hor;

return 1;

}

return 0;

}

};

class Queen: public Bishop, public Castle

{

public:

Queen(char x, int y, int z): //конструктор

Castle (x, y, z), Bishop (x, y, z)

{}

int Move(char x, int y) {

return Castle::Move(x,y) || Bishop::Move (x,y);

}};

В программе определены 4 класса. Класс Figure является абстрактным обобщением свойств всех шахматных фигур, поэтому он содержит такие компонентные данные, как позиция фигуры на доске, определяемая по вертикали буквой vert и по горизонтали цифрой hor, а также цвет фигуры color. Классы Castle и Bishop описывают, соответственно, ладью и слона. Для этих классов определена функция

int Move(char x, int y),

п роверяющая, может ли данная фигура пойти на поле с указанными в параметрах функции координатами, и если может – сделать этот ход. Самым интересным классом является класс Queen, описывающий поведение ферзя. Каждый, кто знаком с правилами шахмат, знает, что ферзь объединяет в себе свойства ладьи и слона (в том смысле, что может ходить как по диагонали, как слон, так и по вертикали и горизонтали, как ладья). Поэтому класс Queen объявлен потомком двух классов: Castle и Bishop. Таким образом, имеется иерархия классов, изображенная на рис.10.

Приведенный пример реализации класса Queen содержит ошибку. Дело в том, что для класса Queen дублируются компонентные данные vert, hor и color, в то время как у реального ферзя всего одна позиция на доске и один цвет. Таким образом, встала задача предотвратить дублирование компонент непрямого базового класса в производном. Решить эту проблему можно, объявив класс Figure виртуальным.

Для того, чтобы определить непрямой базовый класс виртуальным, необходимо при объявлении этого класса базовым в списке порождения указать ключевое слово virtual. Спецификатор virtual способствует минимизации структуры производного класса. Главная особенность виртуальных базовых классов - они не тиражируются. Изменим определение классов шахматных фигур.

class Figure {…};

class Castle: public virtual Figure {…};

class Bishop: public virtual Figure {…};

class Castle: public Castle, public Bishop{…};

Теперь схема иерархии классов выглядит так, как показано на рис.11, и компонентные данные vert, hor, color не будут дублироваться в объектах класса Queen.

При использовании виртуальных классов необходимо обратить внимание на особенность вызова конструкторов базовых классов. Конструктор класса Queen был определен следующим образом:

Queen(char x, int y, int z): Castle (x, y, z), Bishop (x, y, z)

{}

В конструкторе предусмотрен вызов конструкторов прямых базовых классов, которые создают в памяти экземпляры классов Castle и Bishop . В свою очередь, конструкторы классов Castle и Bishop вызывают конструктор своего базового класса (Figure), вследствие чего и создавалось два экземпляра класса Figure. Если класс Figure объявлен виртуальным, конструктор класса Queen необходимо переопределить:

Queen(char x, int y, int z): Castle (x, y, z), Bishop (x, y, z), Figure(x,y,z)

{}

Если Figure – виртуальный класс, то конструкторы классов Castle и Bishop не будут вызывать конструктор класса Figure, а для того, чтобы один экземпляр этого объекта все таки был создан, вызов конструктора класса Figure необходимо поместить непосредственно в определение класса Queen.

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

class A {…};

class B: virtual public A {…};

class C: virtual public A {…};

class D: public A{…};

class E: public A {…};

class F: public B, public C, public D, public E {…};

Схема иерархии для такой системы классов в графической форме приведена на рис.12.

В данном случае объект класса F будет включать три экземпляра класса A: один виртуальный, совместно используемый классами B и С, и два невиртуальных, относящихся к классам E и D.

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