2013-07-09 3 views
0

Просто надеясь, что кто-то может объяснить, почему моя программа не выполняет процедуру Move_Piece для типа Piece, а не процедуру Move_Piece для типа Пруд, когда я пытаюсь переместить пруд. Когда я передаю переменную типа Pond в процедуру Move_Piece, вместо «1» печатается «Использование основного Move_Piece». Почему это?Переопределение и расширение типа

Я использую Ada 2005, в случае, если это не было очевидно из-за ключевого слова overriding. Надеюсь, я не предоставил слишком мало информации. Благодаря!

chess_types.ads:

package Chess_Types is 
    type Color is (Black, White); 
    type Piece is tagged 
    record 
    Name : String (1 .. 3) := " "; 
    Alive : Boolean := False; 
    Team : Color; 
    Coordinate : Integer; 
    end record; 
    procedure Move_Piece(P: in out Piece); 
    -- Board Types 
    type Board_Row is array (Positive range 1 .. 8) of Piece; 
    type Board_Type is array (Positive range 1 .. 8) of Board_Row; 
end Chess_Types; 

chess_types.adb:

with Ada.Text_IO; 
use Ada.Text_IO; 

package body Chess_Types is 
    procedure Move_Piece(P: in out Piece) is 
    begin 
     Put_Line("Using basic Move_Piece"); 
    end Move_Piece; 
end Chess_types; 

chess_types-piece_types.ads:

package Chess_Types.Piece_Types is 

    type Pond is new Piece with 
     record 
     First_Move : Boolean := True; 
     end record; 
    overriding 
    procedure Move_Piece(Po: in out Pond); 

    type Rook is new Piece with null record; 
     overriding 
    procedure Move_Piece(Ro: in out Rook); 

    type Knight is new Piece with null record; 
     overriding 
    procedure Move_Piece(Kn: in out Knight); 

    type Bishop is new Piece with null record; 
     overriding 
    procedure Move_Piece(Bi: in out Bishop); 

    type Queen is new Piece with null record; 
     overriding 
    procedure Move_Piece(Qu: in out Queen); 

    type King is new Piece with null record; 
     overriding 
    procedure Move_Piece(Ki: in out King); 
end Chess_Types.Piece_Types; 

chess_types-piece_types.adb:

with Ada.Text_IO; 
use Ada.Text_IO; 

package body Chess_Types.Piece_Types is 
-- Possible_Moves : array (Integer range 1 .. 100) of Integer range 11 .. 88; 
    procedure Move_Piece(Po: in out Pond) is 
    begin 
     Put_Line("1"); 
    end Move_Piece; 

    procedure Move_Piece(Ro: in out Rook) is 
    begin 
     Put_Line("2"); 
    end Move_Piece; 

    procedure Move_Piece(Kn: in out Knight) is 
    begin 
     Put_Line("3"); 
    end Move_Piece; 

    procedure Move_Piece(Bi: in out Bishop) is 
    begin 
     Put_Line("4"); 
    end Move_Piece; 

    procedure Move_Piece(Qu: in out Queen) is 
    begin 
     Put_Line("5"); 
    end Move_Piece; 

    procedure Move_Piece(Ki: in out King) is 
    begin 
     Put_Line("6"); 
    end Move_Piece; 
end Chess_types.Piece_Types; 

chess.adb:

with Ada.Text_IO; 
with Print_Things; 
with Adjust_Board; 
with Chess_Types; 
with Chess_Types.Piece_Types; 
use Ada.Text_IO; 
use Print_Things; 
use Adjust_Board; 
use Chess_Types; 
use Chess_Types.Piece_Types; 

procedure Chess is 
    Board : Board_Type; 
    Move : String (1 .. 5); 
    Move_From : Integer range 11 .. 88; 
    Move_To : Integer range 11 .. 88; 
begin 

    -- Initialize and Print default board 
    Initialize_Board(Board); 
    Print_Board(Board); 

    -- Get the move 
    Put_Line("Select a move:"); 
    Move := Get_Line; 
    while move /= "Q" loop 
     Move_From := Integer'Value(Move(Move'First .. Move'First + 1)); 
     Move_To := Integer'Value(Move(Move'First + 3 .. Move'Last)); 
     -- Put_Line(Integer'Image(Move_From) & " to" & Integer'Image(Move_To)); 

     -- Associate the move with a piece 
     for I in Board'Range(1) loop 
     for J in Board'Range(1) loop 
      if Move_From = Board(I)(J).Coordinate then 
       Move_Piece(Board(I)(J)); 
      end if; 
     end loop; 
     end loop; 
     -- Print the Board 
     Print_Board(Board); 
     -- Get the move 
     Put_Line("Select a move:"); 
     Move := Get_Line; 
    end loop; 


end Chess; 

adjust_board.adb:

with Chess_Types; 
use Chess_Types; 
with Chess_Types.Piece_Types; 
use Chess_Types.Piece_Types; 
package body Adjust_Board is 

    procedure Initialize_Board(Board: in out Board_Type) is 
     -- Define White Chess Pieces 
     WP1 : Pond := ("wP ", True, White, 12, True); 
     WP2 : Pond := ("wP ", True, White, 22, True); 
     WP3 : Pond := ("wP ", True, White, 32, True); 
     WP4 : Pond := ("wP ", True, White, 42, True); 
     WP5 : Pond := ("wP ", True, White, 52, True); 
     WP6 : Pond := ("wP ", True, White, 62, True); 
     WP7 : Pond := ("wP ", True, White, 72, True); 
     WP8 : Pond := ("wP ", True, White, 82, True); 
     WR1 : Rook := ("wRk", True, White, 11); 
     WR2 : Rook := ("wRk", True, White, 81); 
     WK1 : Knight := ("wKn", True, White, 21); 
     WK2 : Knight := ("wKn", True, White, 71); 
     WB1 : Bishop := ("wBi", True, White, 31); 
     WB2 : Bishop := ("wBi", True, White, 61); 
     WQ : Queen := ("wQu", True, White, 41); 
     WK : King := ("wKi", True, White, 51); 

     -- Define Black Chess Pieces 
     BP1 : Pond := ("bP ", True, Black, 17, True); 
     BP2 : Pond := ("bP ", True, Black, 27, True); 
     BP3 : Pond := ("bP ", True, Black, 37, True); 
     BP4 : Pond := ("bP ", True, Black, 47, True); 
     BP5 : Pond := ("bP ", True, Black, 57, True); 
     BP6 : Pond := ("bP ", True, Black, 67, True); 
     BP7 : Pond := ("bP ", True, Black, 77, True); 
     BP8 : Pond := ("bP ", True, Black, 87, True); 
     BR1 : Rook := ("bRk", True, Black, 18); 
     BR2 : Rook := ("bRk", True, Black, 88); 
     BK1 : Knight := ("bKn", True, Black, 28); 
     BK2 : Knight := ("bKn", True, Black, 78); 
     BB1 : Bishop := ("bBi", True, Black, 38); 
     BB2 : Bishop := ("bBi", True, Black, 68); 
     BQ : Queen := ("bQu", True, Black, 48); 
     BK : King := ("bKi", True, Black, 58); 

    begin 
     -- Initialize Chess Board 
     Board(1)(1) := Piece(WR1); 
     Board(8)(1) := Piece(WR2); 
     Board(2)(1) := Piece(WK1); 
     Board(7)(1) := Piece(WK1); 
     Board(3)(1) := Piece(WB1); 
     Board(6)(1) := Piece(WB1); 
     Board(4)(1) := Piece(WQ); 
     Board(5)(1) := Piece(WK); 
     Board(1)(2) := Piece(WP1); 
     Board(2)(2) := Piece(WP2); 
     Board(3)(2) := Piece(WP3); 
     Board(4)(2) := Piece(WP4); 
     Board(5)(2) := Piece(WP5); 
     Board(6)(2) := Piece(WP6); 
     Board(7)(2) := Piece(WP7); 
     Board(8)(2) := Piece(WP8); 

     Board(1)(8) := Piece(BR1); 
     Board(8)(8) := Piece(BR2); 
     Board(2)(8) := Piece(BK1); 
     Board(7)(8) := Piece(BK1); 
     Board(3)(8) := Piece(BB1); 
     Board(6)(8) := Piece(BB1); 
     Board(4)(8) := Piece(BQ); 
     Board(5)(8) := Piece(BK); 
     Board(1)(7) := Piece(BP1); 
     Board(2)(7) := Piece(BP2); 
     Board(3)(7) := Piece(BP3); 
     Board(4)(7) := Piece(BP4); 
     Board(5)(7) := Piece(BP5); 
     Board(6)(7) := Piece(BP6); 
     Board(7)(7) := Piece(BP7); 
     Board(8)(7) := Piece(BP8); 
    end Initialize_Board; 
end Adjust_Board; 
+0

Вы должны показать нам место, где вы звоните в Move_Piece. В Ada вызывающий абонент решает, посылает вызов или нет. Скорее всего, вы звоните непосредственно на Piece-типа, а не на Piece'Class, который будет отправлять. – egilhh

+0

'Move_Piece (Board (I) (J))' имеет Board_Type, объявленный в chess_types.ads. I и J - это просто цикл, проходящий через двумерный массив, до тех пор, пока Piece не будет найден с теми же координатами на шахматной доске, как тот, который игрок выбрал для перемещения. Я также пробовал «Совет (I) (J) .Move_Piece», но это имело аналогичный эффект. Если этого недостаточно, предположим, я могу скопировать больше кода, связанного с вызовом. – halexh

+0

Декларация типа Board, а также то, как вы заполняете массив, также поможет. (Но поскольку Piece'Class является неопределенным типом, я предполагаю, что он объявлен как массив Piece, который объясняет, почему он не отправляет) – egilhh

ответ

3

В chess_types.ads, добавьте

type Piece_Acc is access all Piece'Class; 

Board_Row должен быть массивом Piece_Acc:

type Board_Row is array (1..8) of Piece_Acc; 

Вы действительно хотите, чтобы элементы в вашем массиве были Piece'Class, но это не работает, поскольку компилятор не может сказать в этот момент, какие типы могут быть получены из Piece и каков их размер памяти, t настроить массив. Поэтому вместо этого он должен быть типом доступа. (В C# или Java все объекты автоматически получают доступ к типам [указателям], хотите ли вы этого или нет. В Ada вам нужно сказать это, когда вы хотите, чтобы объекты были указателями.) Затем, когда вы настраиваете вещи в файле adjust_board.adb, вы 'd say такие вещи, как

Board(1)(1) := new Rook' (WR1); 

и т. д., чтобы создать объект доступа.

[Кроме того, это приведет к тому, что все остальное в Board не инициализируется для инициализации нулем. Если вы хотите, чтобы инициализировать его в какой-то другой части, которая не указывает «не кусок», вам необходимо назначить неиспользованных мест в Совете самостоятельно.]

Но как только все это будет сделано, когда вы говорите

Board(I)(J).Move_Piece; -- same as Board(I)(J).all.Move_Piece; 

или

Move_Piece(Board(I)(J).all); 

тип правления (I) (J) .all тип класса широк, поэтому он направит на правильный Move_Piece, как вы хотите.

Обратите внимание, что если вы сами выделяете «новое», вы также должны нести ответственность за освобождение, чтобы избежать утечек памяти (если все не распределено только один раз, а затем вам все равно). Лучший способ сделать это - контролируемые типы, т. Е. Создание Piece из Ada.Finalization.Controlled.

MORE: способ избежать решения доступа и распределения/открепление вещи сами могли бы использовать Ada.Containers.Indefinite_Vectors вместо массива:

subtype Board_Index is Integer range 1 .. 64; 
package Chessboard is new Ada.Containers.Indefinite_Vectors (Board_Index, Piece'Class); 

Этот пакет не позволяет многомерный типа индексы, поэтому вам нужно будет вычислить один индекс самостоятельно (в диапазоне 1..64 или 0..63) или создать экземпляр Indefinite_Vectors, который, как мне кажется, неудобен. Но это должно устранить необходимость делать ваши собственные распределения, и я думаю, что это также делает освобождение для вас, когда контейнер уничтожен.

+0

P.S. Я отвратительно называю вещи, поэтому, если вы хотите другое имя, чем Piece_Acc, пожалуйста, не стесняйтесь. – ajb

+0

Не могли бы и другие элементы (WR1, WR2 и т. Д.) Быть объявлены по-разному? – halexh

+1

@halexh: Нет, объявляя его ладьей и т. Д., Это то, что вы хотите. И я думаю, что испортил «новый»; это должно быть «Совет (1) (1): = новый ладья» (WR1); '. Компилятор признает, что Rook - это тип в Piece'Class, и это нормально для того, чтобы «доступ ко всему Piece'Class» был доступ к ладье. Я отредактировал свой ответ. – ajb