2012-01-27 57 views
5

我正在做一个国际象棋游戏,我想有一个片段的数组。C++中的Abstract/Base结构?

如果我没错,在Java中可以有一个抽象的Piece类,并且有KingQueen扩展那个类。如果我要制作一排Piece,我可以在该阵列的某处放置King片,并在另一个位置放置Queen片,因为KingQueen都会延伸Piece

有什么办法可以用C++中的结构来做到这一点吗?

+0

结构通常是c,C++给你类和OOP所以我会坚持,因为你是新来的c/c + +。 – L7ColWinters 2012-01-27 06:06:29

+1

@ L7ColWinters:为什么结构不是OOP?为什么你应该使用类呢? – 2012-01-27 06:07:43

+6

@ L7ColWinters:这是一个奇怪的声明。 'struct'和'class'几乎完全相同。 – EboMike 2012-01-27 06:11:44

回答

5

是的。你可以用C++创建一个abstract base class。简单地设置一个或多个的方法是纯虚:

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

然后,您可以创建一个实现纯虚方法

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

通过向类中添加纯虚函数,可以在C++中模拟Abstract class

在C++中,您可以使用可以在类上进行的结构来完成所有任务。
C++中的结构仅在成员的默认访问规范和继承期间与类不同。

1

可以在几乎相同的使用继承在C++中的子类就像你在Java中一样。 C++既有类又有结构,在这种情况下,你可以使用其中一种。

C++中的抽象类只是其中包含纯虚方法的类。这些是没有方法定义的方法。

您的解决方案可能是这个样子:

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

这是无效的C++类语法。您不要在'class'关键字前添加访问说明符。通过将k和q分配给myPieces,您也​​会遇到潜在的拼接问题。 – greatwolf 2012-01-27 06:16:24

+0

对不起,我编辑了一下代码。拼接问题是什么意思? – Oleksi 2012-01-27 06:21:05

+1

看看http://stackoverflow.com/q/274626/234175 – greatwolf 2012-01-27 06:24:38

3

肯定。

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

再后来,

AbstractPiece* array[size]; 

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

你缺少一个虚拟析构函数。 – 2012-01-27 10:27:54

+0

你说得对。我编辑了我的答案。 – Julius 2012-01-27 18:05:15

2

在C++中,你可以使用抽象类或结构:

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

用法:

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

输出:

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

对于一个非常简单的问题,这是一个令人难以置信的复杂答案!你真的需要引入'__PRETTY_FUNCTION__',boost,lambdas,标准算法等吗? – 2012-01-27 10:27:11

+0

@LucTouraille我习惯于使用'__PRETTY_FUNCTION__',因为它显示了类名和参数类型/返回值。通过这种方式很容易看到被调用的内容。至于其他的问题,我真的不想花更多的时间做一个简单的答案,所以我用了第一个想到的东西 - 当然,我可以花更多的时间打字,并使答案更长... – stefanB 2012-01-28 06:20:52

2

我宁愿避免使用指针,你一定要记住清除它们。

本设计使用策略模式。界面是PieceType,它允许您显示板上的有效位置,或显示板上的初始位置。我敢肯定,还有更多你想每一个战略,能够做到:

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

我们只需要每个PieceType之一,因为这种类型的跨棋子共享,也可以是常量:

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

我们使用这些策略来初始化棋子,我们保持一个向量:

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

我包裹起来的代码在自己的功能添加到ChessMan矢量:

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的机会!

+0

问题是关于抽象基类,而不是关于国际象棋游戏的最佳设计。尽管你的回答可能会让你感兴趣的原始海报,但它根本没有解决这个问题。 – 2012-01-27 10:36:02

+0

@LucTouraille我认为使用容器进行同质数据很重要。异构行为更好地存储在别处。所以我把这些指向抽象类的指针放在同类对象中。我认为这是一个很好的原则。如果这个例子太长了,或者我提供了一个完整的解决方案,我很抱歉。你可以自由编辑它,并使其更好。 – 2012-01-27 10:55:00