2012-01-27 62 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