使用继承函数而不是基础(不是抽象)

时间:2015-02-18 16:48:37

标签: c++ inheritance

我希望有一个名为chessmanpawn的课程。我不能让西洋棋棋子成为一个抽象类,因为我需要创建一个2D数组。 pawn类继承chessman,当我写这篇文章时,我需要使用move pawn函数:

chessman *cm = new pawn("a3", 'w');
cm->move(pos);

此代码使用chessman::move。我该怎么做才能使它来自pawn类?我的问题与this question非常相似,但我的函数并没有将pawn作为参数。在Java中,它很容易,因为你可以创建抽象类的数组,但在C ++中它只是令人困惑。

修改

这是西洋棋棋子类的定义(功能已经是虚拟的,你可以看到):

class chessman
{
public:
    int i;
    int j;
    string name;
    char color;
    virtual bool move(string final_pos);
};

和典当:

class pawn : public chessman
{
public:
    pawn(string pos, char color);
    bool move(string final_pos);
};

2 个答案:

答案 0 :(得分:3)

  

我不能让西洋棋棋子成为一个抽象类,因为我需要创建一个2D数组。

是的,你可以。您没有创建chessman个对象数组,而是创建一个指向 chessman个对象的数组。然后chessman可以是抽象的(因为它应该是,因为您不应该直接创建chessman的实例)。

  

pawn类继承了西洋棋棋子,当我写这个

时我需要使用pawn的move函数

多态性为您处理。但是为了使用多态对象数组,数组需要保存指向存储在别处的对象的指针/引用,而不是自己保存实际的对象。

  

在Java中,它很容易,因为你可以创建抽象类的数组,但在C ++中它只是令人困惑。

你在C ++中做同样的事情。在Java中,对象是引用类型,因此它们总是由指针引用(Java语言只是隐藏了您的详细信息)。

尝试这样的事情:

class chessman
{
private:
    virtual bool isValidMove(string final_pos) = 0;

public:
    int i;
    int j;
    string name;
    char color;
    chessman(string aname, char acolor);
    bool move(string final_pos);
};

chessman::chessman(string aname, char acolor)
    : name(aname), color(acolor)
{
}

bool chessman::move(string final_pos)
{
    // validate that final_pos is a valid position on the board...

    // validate that final_pos is a valid position for the piece being moved...
    if (!isValidMove(final_pos))
        return false;

    // move to the position...

    return true;
}

class pawn : public chessman
{
private:
    virtual bool isValidMove(string final_pos);

public:
    pawn(string pos, char color);
};

pawn::pawn(string pos, char color)
    : chessman("pawn", color)
{
    //...
}

bool pawn::isValidMove(string final_pos)
{
    // validate that final_pos is a valid position for this pawn to move to...
    return ...;
}

class rook : public chessman
{
private:
    virtual bool isValidMove(string final_pos);

public:
    rook(string pos, char color);
};

rook::rook(string pos, char color)
    : chessman("rook", color)
{
    //...
}

bool rook::isValidMove(string final_pos)
{
    // validate that final_pos is a valid position for this rook to move to...
    return ...;
}

class knight : public chessman
{
private:
    virtual bool isValidMove(string final_pos);

public:
    knight(string pos, char color);
};

knight::knight(string pos, char color)
    : chessman("knight", color)
{
    //...
}

bool knight::isValidMove(string final_pos)
{
    // validate that final_pos is a valid position for this knight to move to...
    return ...;
}

class bishop : public chessman
{
private:
    virtual bool isValidMove(string final_pos);

public:
    bishop(string pos, char color);
};

bishop::bishop(string pos, char color)
    : chessman("bishop", color)
{
    //...
}

bool bishop::isValidMove(string final_pos)
{
    // validate that final_pos is a valid position for this bishop to move to...
    return ...;
}

class queen : public chessman
{
private:
    virtual bool isValidMove(string final_pos);

public:
    queen(string pos, char color);
};

queen::queen(string pos, char color)
    : chessman("queen", color)
{
    //...
}

bool queen::isValidMove(string final_pos)
{
    // validate that final_pos is a valid position for this queen to move to...
    return ...;
}

class king : public chessman
{
private:
    virtual bool isValidMove(string final_pos);

public:
    king(string pos, char color);
};

king::king(string pos, char color)
    : chessman("king", color)
{
    //...
}

bool king::isValidMove(string final_pos)
{
    // validate that final_pos is a valid position for this king to move to...
    return ...;
}

然后你可以做这样的事情:

chessman* white_pieces[16];
chessman* black_pieces[16];

for (int i = 0; i < 8; ++i)
{
    white_pieces[i] = new pawn(...);
    black_pieces[i] = new pawn(...);
}

for (int i = 8; i < 10; ++i)
{
    white_pieces[i] = new rook(...);
    black_pieces[i] = new rook(...);
}

for (int i = 10; i < 12; ++i)
{
    white_pieces[i] = new knight(...);
    black_pieces[i] = new knight(...);
}

for (int i = 12; i < 14; ++i)
{
    white_pieces[i] = new bishop(...);
    black_pieces[i] = new bishop(...);
}

white_pieces[14] = new queen(...);
black_pieces[14] = new queen(...);

white_pieces[15] = new king(...);
black_pieces[15] = new king(...);

根据需要移动它们:

white_pieces[index]->move(pos);
...
black_pieces[index]->move(pos);

当然,完成后不要忘记清理:

for (int i = 0; i < 16; ++i)
{
    delete white_pieces[i];
    delete black_pieces[i];
}

要自动清理,您可以使用std::auto_ptr<chessman>个对象的数组。或者,在C ++ 11及更高版本中,std::vector / std::arraystd::unique_ptr<chessman>个对象。

答案 1 :(得分:1)

在C ++中,你会在棋盘上创建一个vector(或者在C ++ 11中可能是array的某种指针(指针类型由对象所有权决定),并且西洋棋棋子是抽象的。这只是一种略微不同的思考方式。

(编辑评论很有意思): 要使其选择正确的move函数,请使用基类中的virtual机制。我建议通过不使用公共虚函数将接口与实现分开。而是使用公共非虚拟接口和私有或受保护的虚拟实现。您将使用私有实现,每个子代完全替换功能,而当子类需要也调用父功能时,您将使用protected。