7

I'm making a chess game and I would like to have an array of pieces.

If I'm correct, in Java you can have an abstract Piece class and have King or Queen extend that class. If I were to make an array of Pieces I could place a King piece somewhere in that array and a Queen piece at another spot because both King and Queen extend Piece.

Is there any way to do that with structures in C++?

Austin Moore
  • 1,414
  • 6
  • 20
  • 43

6 Answers6

8

Yes. You can create an abstract base class in C++. Simply set one or more of the methods to be pure virtual:

class Piece {
    public:
        Piece ();
        virtual ~Piece ();
        virtual void SomeMethod () = 0;  // This method is not implemented in the base class, making it a pure virtual method. Subclasses must implement it
 };

You can then create sub-classes that implement the pure virtual methods

class King : public Piece {
    // ... the rest of the class definition
    virtual void SomeMethod (); // You need to actually implement this
};
user1118321
  • 25,567
  • 4
  • 55
  • 86
4

You can simulate an Abstract class in C++ by adding a pure virtual function to an class.

In c++ You can do everything with structures which you can on classes .
A structure in C++ only differs from an class in terms of default access specification for members and during Inheritance.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
3

Sure.

class AbstractPiece
{
public:
virtual void aFunction()=0; //this makes AbstractPiece an abstract class.
virtual ~AbstractPiece();
};

class King : public AbstractPiece
{
public:
virtual void aFunction(); //this is the one that would get called
virtual ~King();
};

And then, later,

AbstractPiece* array[size];

and

array[index] = new King();
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
Jules G.M.
  • 3,624
  • 1
  • 21
  • 35
1

You can use inheritance in C++ in almost the same way as you do in Java. C++ has both classes and structures, and in this case you can use either.

Abstract classes in C++ are just classes with pure virtual methods in them. These are methods without a method definition.

Your solution might look something like this:

class Piece {
public:
   virtual ~Piece ();
   virtual void move() = 0; //this is a pure virtual function, making this an abstract class.
};

class King : public Piece {
public:
   void move() {};
};

class Queen : public Piece {
public:
  void move() {};
};

....

Piece *myPieces[2] = new Piece*[2];
myPieces[0] = new King();
myPieces[1] = new Queen(); 
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
Oleksi
  • 12,947
  • 4
  • 56
  • 80
1

In c++ you can use abstract classes or structures:

#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/construct.hpp>

using namespace std;

struct piece
{
    virtual ~piece() {};
    virtual void dosomething() = 0;
};

struct king : piece
{
    ~king() { cout << __PRETTY_FUNCTION__ << endl; }
    void dosomething() { cout << __PRETTY_FUNCTION__ << endl; }
};

struct queen : piece
{
    ~queen() { cout << __PRETTY_FUNCTION__ << endl; }
    void dosomething() { cout <<  __PRETTY_FUNCTION__ << endl; }
};

struct pawn : piece
{
    ~pawn() { cout << __PRETTY_FUNCTION__ << endl; }
    void dosomething() { cout << __PRETTY_FUNCTION__ << endl; }
};

Usage:

int main()
{
    typedef std::vector< piece * > pieces_t;
    pieces_t pieces;
    pieces.push_back(new queen());
    pieces.push_back(new king());
    pieces.push_back(new pawn());
    pieces.push_back(new pawn());
    pieces.push_back(new pawn());
    pieces.push_back(new pawn());

    // calling dosomething()
    std::for_each(pieces.begin(), pieces.end(), 
          boost::lambda::bind(&piece::dosomething, boost::lambda::_1));

    // destructing
    std::for_each(pieces.begin(), pieces.end(), 
          boost::lambda::bind(boost::lambda::delete_ptr(), boost::lambda::_1));
}

Output:

virtual void queen::dosomething()
virtual void king::dosomething()
virtual void pawn::dosomething()
virtual void pawn::dosomething()
virtual void pawn::dosomething()
virtual void pawn::dosomething()
virtual queen::~queen()
virtual king::~king()
virtual pawn::~pawn()
virtual pawn::~pawn()
virtual pawn::~pawn()
virtual pawn::~pawn()
stefanB
  • 77,323
  • 27
  • 116
  • 141
  • This is an incredibly complex answer to a very simple question! Did you really need to introduce `__PRETTY_FUNCTION__`, boost, lambdas, standard algorithms, etc.? – Luc Touraille Jan 27 '12 at 10:27
  • @LucTouraille I'm used to using `__PRETTY_FUNCTION__` because it shows the class name and parameter types/return values. This way it's easy to see what gets called. As for the rest, I didn't really want to spend more time for a simple answer so I used what first came to my mind - of course I could spend more time typing and make the answer lengthier .... – stefanB Jan 28 '12 at 06:20
1

I prefer to avoid using pointers as you have to remember to clean them up.

This design uses the strategy pattern. The interface is PieceType, which allows you to display valid positions on a board, or show the initial positions on the board. I'm sure there's more you would want each strategy to be able to do:

class Board;

class PieceType
{
public:
    virtual showValidMoves(Board& board) const = 0;
    virtual showInitialPosition(Board& board) const = 0;
    // ...  
};

class Pawn : public PieceType
{
public:
    virtual showValidMoves(Board& board) const;
    virtual showInitialPosition(Board& board) const;
    // ...
};

class Rook : public PieceType
{
    // ...
};
//...

We only need one of each PieceType, and as that type is shared across chessmen, it can also be const:

const Pawn PAWN;
const Rook ROOK;
const Knight KNIGHT;

We use these strategies to initialise the Chessmen we keep in a vector:

class ChessMan
{
public:
    enum Colour {Black, White};

    ChessMan(const Colour& colour, PieceType& pieceType);

    void showValidMoves(Board& board);
    void showInitialPosition(Board& board);
private:
    Colour m_colour;
    PieceType& m_pieceType;
};

I'll wrap up the code for adding a ChessMan to a vector in its own function:

void add(vector<ChessMan>& chessmen,
         const ChessMan::Colour& colour,
         const PieceType& pieceType,
         const unsigned int amount)
{
    chessmen.insert(chessmen.end(), ChessMan(colour, pieceType), amount);
}

void main()
{
    using std::vector;

    vector<ChessMan> chessmen;
    add(chessmen, 16, ChessMan::Black, PAWN);
    add(chessmen, 2, ChessMan::Black, ROOK);
    add(chessmen, 2, ChessMan::Black, KNIGHT);
    //...
}

Bonne chance!

Peter Wood
  • 23,859
  • 5
  • 60
  • 99
  • The question is about abstract base classes, not about the best design for a chess game. Even though your answer could interest the original poster, it does not address the question at all. – Luc Touraille Jan 27 '12 at 10:36
  • @LucTouraille I think it's important to use containers for homogeneous data. The heterogeneous behaviour is better stored elsewhere. So I've put the pointers to the abstract class inside the homogeneous objects. I think it's a good principle. I'm sorry if the example was too long, or looked like I was providing a whole solution. You're free to edit it and make it better. – Peter Wood Jan 27 '12 at 10:55