2012-01-27 32 views
5

Estoy haciendo un juego de ajedrez y me gustaría tener una variedad de piezas.Resumen/Estructura base en C++?

Si estoy en lo correcto, en Java puede tener una clase abstracta Piece y tener King o Queen extender esa clase. Si tuviera que hacer una matriz de Piece s podría colocar una pieza King en algún lugar de esa matriz y una pieza Queen en otro lugar porque tanto King como Queen extienden Piece.

¿Hay alguna manera de hacer eso con estructuras en C++?

+0

las estructuras son generalmente para c, C++ le da clases y OOP, así que me apegaré a eso ya que es nuevo en c/C++. – L7ColWinters

+1

@ L7ColWinters: ¿Por qué las estructuras no son OOP? ¿Por qué deberías usar clases en su lugar? –

+6

@ L7ColWinters: Esa es una declaración extraña. 'struct' y' clase' son casi idénticos. – EboMike

Respuesta

5

Sí. Puede crear un abstract base class en C++. Basta con establecer uno o más de los métodos a ser puro 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 
}; 

A continuación, puede crear sub-clases que implementan los métodos virtuales puros

class King : public Piece { 
    // ... the rest of the class definition 
    virtual void SomeMethod(); // You need to actually implement this 
}; 
4

Puede simular Abstract class en C++ agregando una función virtual pura a una clase.

En C++ Puede hacer todo lo posible con las estructuras que puede en las clases.
Una estructura en C++ solo difiere de una clase en términos de especificación de acceso predeterminado para los miembros y durante la herencia.

1

Puede utilizar la herencia en C++ en casi la misma como lo haces en Java. C++ tiene ambas clases y estructuras, y en este caso puede usar cualquiera de ellas.

Las clases abstractas en C++ son solo clases con métodos virtuales puros en ellas. Estos son métodos sin una definición de método.

Su solución podría ser algo como esto:

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(); 
+0

que no es válido C++ sintaxis de clase No antepone los especificadores de acceso delante de la palabra clave 'class'. También tendrá un problema potencial de empalme asignando k y q a myPieces de esa manera. – greatwolf

+0

Lo siento, he editado el código un poco. ¿A qué te refieres con empalmar el problema? – Oleksi

+1

eche un vistazo a http://stackoverflow.com/q/274626/234175 – greatwolf

3

Claro.

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(); 
}; 

Y luego, más tarde,

AbstractPiece* array[size]; 

y

array[index] = new King(); 
+3

Falta un destructor virtual. –

+0

Tienes razón. Edité mi respuesta. – Julius

2

en C++ se puede usar clases abstractas o estructuras:

#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; } 
}; 

Uso:

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)); 
} 

Salida:

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() 
+0

¡Esta es una respuesta increíblemente compleja a una pregunta muy simple! ¿Realmente necesitas introducir '__PRETTY_FUNCTION__', boost, lambdas, algoritmos estándar, etc.? –

+0

@LucTouraille Estoy acostumbrado a usar '__PRETTY_FUNCTION__' porque muestra el nombre de clase y los tipos de parámetros/valores devueltos. De esta manera es fácil ver lo que se llama. En cuanto al resto, realmente no quería dedicar más tiempo a una respuesta simple, así que usé lo primero que me vino a la mente, por supuesto, podría pasar más tiempo escribiendo y hacer que la respuesta sea más larga ... – stefanB

2

que prefieren evitar el uso de punteros que usted tiene que recordar a limpiarlos.

Este diseño utiliza el patrón de estrategia. La interfaz es PieceType, que le permite mostrar posiciones válidas en un tablero, o mostrar las posiciones iniciales en el tablero.Estoy seguro de que hay más le gustaría que cada estrategia que sea capaz de hacer:

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 
{ 
    // ... 
}; 
//... 

tan solo hay uno de cada PieceType, y como ese tipo se comparte a través de piezas de ajedrez, también puede ser const:

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

utilizamos estas estrategias para inicializar el ajedrez tenemos en un 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; 
}; 

voy a envolver el código para añadir un ChessMan a un vector en su propia función :

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!

+0

La pregunta es sobre clases base abstractas, no sobre el mejor diseño para un juego de ajedrez. Aunque su respuesta podría interesar al afiche original, no aborda la pregunta en absoluto. –

+0

@LucTouraille Creo que es importante usar contenedores para datos homogéneos. El comportamiento heterogéneo se almacena mejor en otro lugar. Así que puse los punteros a la clase abstracta dentro de los objetos homogéneos. Creo que es un buen principio. Lo siento si el ejemplo fue demasiado largo o si parecía que estaba proporcionando una solución completa. Eres libre de editarlo y hacerlo mejor. –