- •Введение
- •Как получить исходные тексты
- •Что требуется знать для чтения книги
- •Предисловие к первому изданию
- •Благодарности
- •1.3.Новая парадигма
- •Что читать дальше
- •Упражнения
- •2.7.3.Зацепление и связность
- •2.9. Выбор представления данных
- •Упражнения
- •Глава 3 Классы и методы
- •Упражнения
- •Глава 4 Сообщения, экземпляры и инициализация
- •Упражнения
- •Глава 5 Учебный пример: задача о восьми ферзях
- •Упражнения
- •Глава 6 Учебный пример: игра «Бильярд»
- •Упражнения
- •Глава 7 Наследование
- •7.6.Издержки наследования
- •Упражнения
- •Глава 8 Учебный пример: Пасьянс
- •8.4.1.Основание SuitPile
- •8.4.2.Колода DeckPile
- •Упражнения
- •9.1.1. «Быть экземпляром» и «включать как часть»
- •Упражнения
- •Глава 10 Подклассы и подтипы
- •Упражнения
- •Глава 11 Замещение и уточнение
- •Упражнения
- •Глава 12 Следствия наследования
- •Упражнения
- •Глава 13 Множественное наследование
- •13.1.Комплексные числа
- •Литература для дальнейшего чтения
- •Упражнения
- •Глава 14 Полиморфизм
- •Полиморфные переменные
- •Виртуальное и невиртуальное переопределение
- •Параметрическая перегрузка
- •Отложенные методы в C++
- •Обобщенные функции и шаблоны
- •Полиморфные переменные
- •Отложенные методы в Object Pascal
- •Полиморфные переменные
- •Отложенные методы в Objective-C
- •Полиморфные переменные
- •Отложенные методы в Smalltalk
- •Упражнения
- •Глава 15 Учебный пример: контейнерные классы
- •Упражнения
- •Глава 16 Пример: STL
- •Упражнения
- •Глава 17 Видимость и зависимость
- •Родственные экземпляры
- •Дружественные функции
- •Пространства имен
- •Постоянные члены
- •Упражнения
- •Глава 18 Среды и схемы разработки
- •18.1.1. Java API
- •Упражнения
- •19.5.Класс application
- •19.5.1.Класс button
- •Упражнения
- •Глава 20 Новый взгляд на классы
- •20.2.2.Класс Class
- •Упражнения
- •Глава 21 Реализация объектно-ориентированных языков
- •Литература для дальнейшего чтения
- •Упражнения
- •А.1. «Задача о восьми ферзях» на языке Apple Object Pascal
- •A.3. «Задача о восьми ферзях» на языке Java
- •A.3.1. HTML-файл для апплета Java
- •A.4. «Задача о восьми ферзях» на языке Objective-C
- •A.5. «Задача о восьми ферзях» на языке Smalltalk
- •Б.1. Версия без использования наследования
- •Б.2. Версия с использованием наследования
- •Глоссарий
converted to PDF by BoJIoc
begin
done := false while not done do begin
systemTask;
ignore := GetNextEvent(everyEvent, event); case event.what of
(* выйти и прекратить работу *) keyDown : done := true; mouseDown : begin
localPoint := event.where; GlobalToLocal(localPoint); mouseButtonDown(localPoint.h, localPoint.v);
end;
updateEvt: drawBoard; end; (* case *)
end;
end; begin
MaxApplZone;
InitGraf(@qd.thePort);
InitWindows;
InitCursor;
createGlobals;
createWindow;
eventLoop;
end.
Б.2. Версия с использованием наследования
(*
Программа, моделирующая игру «Бильярд» Демонстрирует объектные свойства языка Object Pascal
Автор: Тимоти Бадд, университет штата Орегон, сентябрь 1995 *)
Program billiards; USES
Windows; type
GraphicalObject = object (* поля данных *)
link : GraphicalObject; region : rect;
(* процедура инициализации *)
procedure setRegion(left, top, right, bottom : integer); (* операции с графическими объектами *)
procedure draw; procedure erase; procedure update;
function intersect(anObj : GraphicalObject) : boolean; procedure hitBy(aBall : GraphicalObject);
end;
Ball = object (GraphicalObject)
(* данные, которые содержатся в объектах-шарах *) direction : real;
energy : real;
(* процедура инициализации *)
converted to PDF by BoJIoc
procedure initialize(x, y : integer); (* методы общего характера *)
procedure draw; override; procedure erase; override; procedure update; override;
procedure hitBy(aBall : GraphicalObject); override; procedure setCenter(newx, newy : integer); procedure setDirection(newDirection : real);
(* вернуть координаты x и y центра шара *) function x : integer;
function y : integer; end;
CueBall = object (Ball)
(* изменяется только подпрограмма рисования *) procedure draw; override;
end;
Wall = object (GraphicalObject)
(* коэффициент отражения ударяющихся шаров *) convertFactor : real;
(* процедура инициализации *) procedure initialize
(left, top, right, bottom : integer; cf : real); (* нарисовать стенку *)
procedure draw; override;
(* известить стенку, что в нее попал шар *) procedure hitBy(aBall : GraphicalObject); override;
end;
Hole = object (GraphicalObject)
(* инициализировать положение лузы *) procedure initialize(x,y : integer); (* нарисовать лузу *)
procedure draw; override;
(* известить лузу, что в нее попал шар *) procedure hitBy(aBall : GraphicalObject); override;
end; var
cueBall : Ball; saveRack : integer; ballMoved : boolean;
listOfObjects : GraphicalObject; theWindow : windowPtr;
procedure GraphicalObject.setRegion (left, top, right, bottom : integer);
begin
SetRect(region, left, top, right, bottom); end;
procedure GraphicalObject.draw; begin
end;
procedure GraphicalObject.erase; begin
EraseRect(region);
end;
procedure GraphicalObject.update; begin
end;
procedure GraphicalObject.hitBy(aBall : GraphicalObject);
converted to PDF by BoJIoc
begin end;
procedure GraphicalObject.intersect (anObj : GraphicalObject) : boolean;
var
theIntersection : Rect; begin
intersect := SetRect(region, anObj.region, theIntersection); end;
procedure Wall.hitBy(anObj : GraphicalObject); var
aBall : Ball; begin
if Member(anObj, Ball) then begin
aBall := Ball(anObj);
(* отразить шар от стенки *) aBall.setDirection(convertFactor — aBall.direction);
end;
end;
procedure Hole.hitBy(anObj : GraphicalObject); var
aBall : Ball; begin
if Member(anObj, Ball) then begin
aBall := Ball(anObj);
(* забрать энергию шара *) aBall.energy := 0.0; aBall.erase;
(* передвинуть шар *) if aBall = cueBall then
aBall.setCenter(50, 100) else begin
saveRack := saveRack + 1; asBall.setCenter(10 + saveRack*15, 250);
end;
(* перерисовать шар заново *) aBall.draw;
end;
end;
procedure Ball.update; var
gptr : GraphicalObject; dx, dy : integer;
i : integer; begin
if energy > 0.5 then begin
ballMoved := true;
(* удалить шар с экрана *) erase;
(* уменьшить энергию *) energy := energy — 0.05;
(* передвинуть шар *)
dx := trunc(5.0*cos(direction)); dy := trunc(5.0*sin(direction));
converted to PDF by BoJIoc
offsetRect(region, dx, dy); (* перерисовать шар *)
for i := 1 to 25 do draw;
(* проверить, не стукнули ли мы чего-нибудь *) gptr := listOfHoles;
while (gptr <> nil) do begin
if gptr <> self then begin
if self.intersect(gptr) then begin
gptr.hitBy(self);
end;
end;
gptr :=gptr.link; end;
end;
end;
procedure Ball.hitBy(anObj : GraphicalObject); var
aBall : Ball; da : real;
begin
if Member(anObj, Ball) then begin
aBall := Ball(anObj);
(* уменьшить энергию ударяющегося шара вдвое *) aBall.energy := aBall.energy / 2.0;
(* и прибавить ее к собственной *) energy := energy + aBall.energy;
(* задать новое направление *)
direction := hitAngle(self.x — aBall.x, self.y — aBall.y); (* направить налетевший шар *)
da := aBall.direction — direction; aBall.setDirection(aBall.direction + da); update;
end;
end;
procedure Ball.draw; begin
(* нарисовать окружность *) FrameOval(region)
end;
procedure CueBall.draw; begin
(* нарисовать закрашенный круг *) PaintOval(region);
end;
procedure mouseButtonDown(x, y : integer); var
gptr : GraphicalObject; begin
(* придать белому шару некоторую начальную энергию *) cueBall.energy := 20.0;
(* и направление *)
cueBall.setDirection( hitAngle(cueBall.x — x, cueBall.y — y));
converted to PDF by BoJIoc
(* цикл до тех пор, пока что-либо движется *) ballMoved := true;
while ballMoved do begin
ballMoved := false; gptr := listOfObjects; while bptr <> nil do begin
gptr.update;
gptr := gptr.link; end;
end;
end;
procedure CreateGlobals; var
i, j : integer; newBall : Ball; newWall : Wall; newHole : Hole;
begin
saveRack := 0; listOfObjects := nil;
(* создать стенки *) new (newWall);
newWall.initialize(10, 10, 300, 15, 0.0); newWall.link := listOfObjects; listOfObjects := newWall;
new (newWall);
newWall.initialize(10, 200, 300, 205, 0.0); newWall.link := listOfObjects; listOfObjects := newWall;
new (newWall);
newWall.initialize(10, 10, 15, 200, 3.14159265359); newWall.link := listOfObjects;
listOfObjects := newWall; new (newWall);
newWall.initialize(300, 10, 305, 205, 3.14159265359); newWall.link := listOfObjects;
listOfObjects := newWall; (* создать лузы *)
new (newHole); newHole.initialize(15, 15); newHole.link := listOfObjects; listOfObjects := newHole;
new (newHole); newHole.initialize(15, 200); newHole.link := listOfObjects; listOfObjects := newHole;
new (newHole); newHole.initialize(300, 15); newHole.link := listOfObjects; listOfObjects := newHole;
new (newHole); newHole.initialize(300, 200); newHole.link := listOfObjects; listOfObjects := newHole;
(* создать шары *)
converted to PDF by BoJIoc
new (cueBall); cueBall.initialize(50, 96); cueBall.link := listOfObjects; listOfObjects := cueBall;
for i := 1 to 5 do begin
for j := 1 to i do begin
new (newBall); newBall.initialize(190 + i*8,
100 + 16*j — 8*i); newBall.link := listOfObjects; listOfObjects := newBall;
end;
end;
end;
procedure drawBoard; var
gptr : GraphicalObject; begin
SetPort(theWindow); gptr := listOfObjects; while (gptr <> nil) do begin
gptr.draw;
gptr := gptr.link; end;
end;
Приложение С
Исходный код программ для карточного пасьянса
Программа карточного пасьянса из главы 8 написана на языке Java со стандартной библиотекой API.
В.1. HTML-файл для апплета
<html>
<title>Solitare Game</title>
<applet code="Solitare.class" width=400 height=500> </applet>
</html>
В.2. Файл Solitare.java
/*
Карточный пасьянс на языке Java
Автор: Тимоти Бадд, университет штата Орегон, 1996
*/
import java.awt.*; import java.applet.*;
converted to PDF by BoJIoc
class Card
{
// конструктор
Card (int sv, int rv)
{
s = sv; r = rv;
faceup = false;
} // доступ к атрибутам карты public int rank ()
{
return r;
}
public int suit()
{
return s;
}
public boolean faceUp()
{
return faceup;
}
public void flip()
{
faceup = ! faceup;
}
public int color()
{
if (suit() == heart || suit() == diamond) return red;
return black;
}
public void draw (Graphics g, int x, int y)
{
String names[] = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};
//очистить прямоугольник, нарисовать границу g.clearRect(x, y, width, height); g.setColor(Color.black);
g.drawRect(x, y, width, height);
//нарисовать карту
if (faceUp())
{
if (color() == red) g.setColor(Color.red);
else g.setColor(Color.blue);
g.drawString(names[rank()], x+3, y+15); if (suit() == heart)
{
g.drawLine(x+25, y+30, x+35, y+20); g.drawLine(x+35, y+20, x+45, y+30); g.drawLine(x+45, y+30, x+25, y+60); g.drawLine(x+25, y+60, x+5, y+30); g.drawLine(x+5, y+30, x+15, y+20); g.drawLine(x+15, y+20, x+25, y+30);
}
else if (suit() == spade)
converted to PDF by BoJIoc
{
g.drawLine(x+25, y+20, x+40, y+50); g.drawLine(x+40, y+50, x+10, y+50); g.drawLine(x+10, y+50, x+25, y+20); g.drawLine(x+23, y+45, x+20, y+60); g.drawLine(x+20, y+60, x+30, y+60); g.drawLine(x+30, y+60, x+27, y+45);
}
else if (suit() == diamond)
{
g.drawLine(x+25, y+20, x+40, y+40); g.drawLine(x+40, y+40, x+25, y+60); g.drawLine(x+25, y+60, x+10, y+40); g.drawLine(x+10, y+40, x+25, y+20);
}
else if (suit() == club)
{
g.drawOval(x+20, y+25, 10, 10); g.drawOval(x+25, y+35, 10, 10); g.drawOval(x+15, y+35, 10, 10); g.drawLine(x+23, y+45, x+20, y+55); g.drawLine(x+20, y+55, x+30, y+55); g.drawLine(x+30, y+55, x+27, y+45);
}
}
else // картинка вниз
{
g.setColor(Color.yellow); g.drawLine(x+15, y+5, x+15, y+65); g.drawLine(x+35, y+5, x+35, y+65); g.drawLine(x+5, y+20, x+45, y+20); g.drawLine(x+5, y+35, x+45, y+35); g.drawLine(x+5, y+50, x+45, y+50);
}
}
// поля данных |
для цветов и мастей |
|
final static int |
width |
= 50; |
final static int |
height = 70; |
|
final static int |
red |
= 0; |
final static int |
black |
= 1; |
final static int |
heart |
= 0; |
final static int |
spade |
= 1; |
final static int |
diamond = 2; |
|
final static int |
club |
= 3; |
// поля данных private boolean faceup; private int r;
private int s; public Card link;
}
class CardPile
{
CardPile (int x1, int y1)
{
x = x1; y = y1;
firstCard = null;
converted to PDF by BoJIoc
}
// функции доступа к картам не переопределяются public Card top()
{
return firstCard;
}
public boolean empty()
{
return firstCard == null;
}
public Card pop()
{
Card result = null; if (firstCard != null)
{
result = firstCard; firstCard = firstCard.link;
}
return result;
}
// следующие методы иногда переопределяются public boolean includes (int tx, int ty)
{
return x <= tx && tx <= x + Card.width && y <= ty && ty <= y + Card.height;
}
public void select (int tx, int ty)
{
// ничего не делает
}
public void addCard (Card aCard)
{
aCard.link = firstCard; firstCard = aCard;
}
public void display (Graphics g)
{
g.setColor(Color.black); if (firstCard == null)
g.drawRect(x, y, Card.width, Card.height); else
firstCard.draw(g, x, y);
}
public boolean canTake (Card aCard)
{
return false;
}
// координаты стопки protected int x; protected int y; private Card firstCard;
}
class DeckPile extends CardPile
{
DeckPile (int x, int y)
{
// вначале инициализировать как родителя
converted to PDF by BoJIoc
super(x, y);
//затем создать новую колоду карт
//сначала положим карты в локальную стопку
CardPile pileOne = new CardPile(0, 0); CardPile pileTwo = new CardPile(0, 0); int count = 0;
for (int i = 0; i < 4; i++) for (int j = 0; j <= 12; j++)
{
pileOne.addCard(new Card(i, j)); count++;
}
//затем вытаскиваем карты произвольным образом for (; count > 0; count--)
{
int limit = ((int)(Math.random() * 1000)) % count;
//передвинуть карту вниз на случайное место
for (int i = 0; i < limit; i++) pileTwo.addCard(pileOne.pop());
// затем добавить карту, найденную здесь addCard(pileOne.pop());
// теперь положить обратно while (! pileTwo.empty())
pileOne.addCard(pileTwo.pop());
}
}
public void select (int tx, int ty)
{
if (empty()) return; Solitare.discardPile.addCard(pop());
}
}
class DiscardPile extends CardPile
{
DiscardPile (int x, int y)
{
super (x, y);
}
public void addCard (Card aCard)
{
if (! aCard.faceUp()) aCard.flip(); super.addCard(aCard);
}
public void select (int tx, int ty)
{
if (empty()) return;
Card topCard = pop();
for (int i = 0; i < 4; i++)
if (Solitare.suitPile[i].canTake(topCard))
{
Solitare.suitPile[i].addCard(topCard);
return;
}
for (int i = 0; i < 7; i++)
if (Solitare.tableau[i].canTake(topCard))
{
converted to PDF by BoJIoc
Solitare.tableau[i].addCard(topCard);
return;
}
//эту карту некуда перекладывать
//положить ее обратно addCard(topCard);
}
}
class SuitPile extends CardPile
{
SuitPile (int x, int y)
{
super (x, y);
}
public boolean canTake (Card aCard)
{
if (empty())
return aCard.rank() == 0; Card topCard = top();
return (aCard.suit() == topCard.suit()) && (aCard.rank() == 1 + topCard.rank());
}
}
class TablePile extends CardPile
{
TablePile (int x, int y, int c)
{
super(x, y);
//инициализировать как родительский класс
//затем инициализировать нашу стопку for (int i = 0; i < c; i++)
{
addCard(Solitare.deckPile.pop());
}
//открыть самую верхнюю карту top().flip();
}
public boolean canTake (Card aCard)
{
if (empty())
return aCard.rank() == 12; Card topCard = top();
return (aCard.color() != topCard.color()) && (aCard.rank() == topCard.rank() — 1);
}
public boolean includes (int tx, int ty)
{
// не проверять нижнюю карту
return x <= tx && tx <= x + Card.width && y <= ty;
}
public void select (int tx, int ty)
{
if (empty()) return;
//если карта закрыта, перевернем
Card topCard = top();
converted to PDF by BoJIoc
if (! topCard.faceUp())
{
topCard.flip();
return;
}
//иначе посмотреть, можно ли переместить
//в основание
topCard = pop();
for (int i = 0; i < 4; i++)
if (Solitare.suitPile[i].canTake(topCard))
{
Solitare.suitPile[i].addCard(topCard);
return;
}
//иначе посмотреть, можно ли переместить
//в другую стопку расклада
for (int i = 0; i < 7; i++)
if (Solitare.tableau[i].canTake(topCard))
{
Solitare.tableau[i].addCard(topCard);
return;
}
// иначе положить обратно addCard(topCard);
}
private int stackDisplay(Graphics g, Card aCard)
{
int localy;
if (aCard == null) return y;
localy = stackDisplay(g, aCard.link); aCard.draw(g, x, localy);
return localy + 35;
}
public void display (Graphics g)
{
stackDisplay(g, top());
}
}
public class Solitare extends Applet
{
static DeckPile deckPile; static DiscardPile discardPile; static TablePile tableau[]; static SuitPile suitPile[]; static CardPile allPiles[]; public void init()
{
//вначале разместить массивы allPiles = new CardPile[13]; suitPile = new SuitPile[4]; tableau = new TablePile[7];
//затем заполнить их
allPiles[0] = deckPile = new DeckPile(335, 5); allPiles[1] = discardPile = new DiscardPile(268, 5);
for (int i = 0; i < 4; i++) allPiles[2+i] = suitPile[i] =