【问题标题】:How to make the base class call overriden function from child class如何使基类从子类调用覆盖函数
【发布时间】:2019-12-18 20:48:09
【问题描述】:

我有一个班级名称Piece,其中有许多子班级,例如RookKnightKing 等... Piece 类有一个名为Move(int x, int y) 的虚函数,所有子类都继承了这个函数。 现在我有了另一个函数,我们称之为foo(Piece& src, Piece& dest)foo() 这样调用函数move()

int foo(Piece& src, Piece& dest)
{
    int moveCode = src.move(dest.getX(), dest.getY());
    // Rest of the code ...
}

函数foo() 有时会获取knight 类作为参数,或King 类或其余子类。 我的问题是当我调用move() 时,我希望它从子类调用重写的move 函数,而是从基类Piece 调用move 类。 有没有办法让src.move()调用子函数?

Piece.h:

class Piece
{
    protected:
        int _pieceTypeIndex;
        int _pieceColor;
        int _x;
        int _y;
    public:
        Piece();
        Piece(int x, int y);
        Piece(int x, int y, int pieceTypeIndex, int pieceColor);
        virtual int move(int dest_x, int dest_y);
        int getPieceTypeIndex() const;
        int getPieceColor() const;
        void setPieceTypeIndex(int pieceTypeIndex);
        void setPieceColor(int pieceColor);
        int getX();
        int getY();
        void setX(int x);
        void setY(int y);
        Piece& operator=(Piece& other);
};

子类代码(Rook.h):

class Rook : public Piece
{
public:
    Rook(int x, int y, int pieceTypeIndex, int pieceColor);
    virtual int move(int dest_x, int dest_y);
};

【问题讨论】:

  • @Mat 抱歉,这是我在这里写的代码中的错误,Board& board 不在代码中。我被黑了,不小心复制了它。我现在解决了这个问题。
  • 无关:我认为不需要赋值运算符。当您不需要打开可避免错误的可能性时,编写赋值运算符。如果您出于上述原因需要它,那么the Rule of Three 建议您有一个复制构造函数和一个析构函数。
  • @0xBlackMirror 你有没有从你得到的答案中得到什么?

标签: c++ class oop inheritance


【解决方案1】:

签名不同。它们必须相同。你的Rook 需要变成这样:

class Rook : public Piece
{
public:
    Rook(int x, int y, int pieceTypeIndex, int pieceColor);
    virtual int move(int dest_x, int dest_y);
};

验证您是否正确执行此操作的一个好方法是使用关键字override

class Rook : public Piece
{
public:
    Rook(int x, int y, int pieceTypeIndex, int pieceColor);
    virtual int move(int dest_x, int dest_y) override;
    virtual int move(int dest_x, int dest_y, Board& board) override; //Wouldn't compile
};

【讨论】:

  • 对不起,这是我在这里写的代码中的错误,Board& board 不在代码中。我被黑了,不小心复制了它。我现在解决了这个问题。
  • @0xBlackMirror 如果真的是这样的话,那段代码就可以工作了。
  • @Rosme,我不重载函数的一个原因是与虚拟/覆盖混合时
  • @umlcat 这只是向他展示的示例代码。但是,考虑到他更改了原始问题的代码,这个答案不再适合。
  • @Rosme 但是当调用src.move(dest.getX(), dest.getY()) 时,它仍然从Piece 调用原始函数,而不是从孩子调用。
【解决方案2】:

如何让基类调用覆盖子类的函数

您只需调用它 - 如果基类不知道如何执行任务的任何部分,则使函数纯虚拟(这也使您的基类抽象 - 它不能被实例化,这是一个好东西)。还要尽量避免幻数。命名您可以更容易阅读代码的内容。

在这种情况下,您还可以依赖隐式创建的复制构造函数/赋值运算符。在您的基类中使用的所有类型都可以轻松复制。

这是一个示例,说明如何将 move() 函数拆分为一个基类部分和一个只有派生类可以处理的部分,移动验证,并让基类 move() 调用 @987654323 @ 在派生类中。

#include <iostream>

// name stuff
enum piece_t { rook, knight, king /* etc */ };
enum color_t { c_black, c_white };

class Piece {
    private:
        // You probably can make these private:
        piece_t _pieceTypeIndex;
        color_t _pieceColor;
        int _x;
        int _y;

    protected:
        // No need to have this public - it's never going to be used by anything
        // but derived classes.
        Piece(int x, int y, color_t pieceColor, piece_t pieceTypeIndex) :
            _pieceTypeIndex(pieceTypeIndex),
            _pieceColor(pieceColor),
            _x(x),
            _y(y)
        {}

    public:
        Piece() = default; // this is questionable

        // Pure virtual - must be implemented by derived classes
        virtual bool validate_move(int dest_x, int dest_y) = 0;

        bool move(int dest_x, int dest_y) {
            // Call the validate_move function in the derived class
            if(validate_move(dest_x, dest_y)==false) return false;

            // Do the rest of the stuff that happens when you move
            // that the base class can actually handle
            _x = dest_x;
            _y = dest_y;
            return true;
        }

        int getX() const { return _x; }
        int getY() const { return _y; }

        // the rest of the functions excluded for brevity
};

class Rook : public Piece {
public:
    using Piece::Piece; // use base class constructors (default ctor - perhaps not needed)

    // The Rook constructor only needs position and color since it already knows
    // that it's a rook and can supply that info to the base class constructor.
    Rook(int x, int y, color_t c) : Piece(x, y, c, rook) {}

    // Implementation of the function that's pure virtual in base.
    // Use "override" to make sure that you actually override. Then compiler
    // will complain if you try to override something that isn't virtual.
    bool validate_move(int /*dest_x*/, int /*dest_y*/) override {
        // validate if this move is ok or not
        return true;
    }
};

int main() {
    Rook a(2, 1, c_black); // no need to specify pieceTypeIndex
    Rook b;                // default, uninitialized - not even a proper Rook at this time
    b = a;                 // copy assignment - now it's a Rook
    Rook c(b);             // copy construction

    std::cout << c.getX() << ' ' << c.getY() << '\n';

    if(c.move(3,4))        // silly move for a rook, but validate_move approves anything :)
        std::cout << "successfully moved to " << c.getX() << ' ' << c.getY() << '\n';
}

【讨论】:

    【解决方案3】:

    您需要在 base 类中声明相同的函数/方法,将该函数标记为 virtual,并在子类中重新声明相同的函数,同时标记为 virtualoverride关键字。

    **Pieces.hpp**
    
    class Piece
    {
      // ...
    
      public:
    
      virtual int move (int x, int y);
    
      void start(int x, int y);
    
      // ...
    
      } // class
    
    class Rook : public Piece
    {
      // ...
    
      public:
    
      virtual int move (int x, int y) override;
    
      // ...
    
      } // class
    
    **Pieces.cpp**
    
    void piece::start(int x, int y)
    {
      this::move(x, y);
    } //
    

    但是,这不能在“C++”的构造方法中完成。

    int main (...)
    {
      Piece MyPiece = new Rook( );
      MyPiece->Start(1, 1);
      free MyPiece ( );
    
      return 0;
    }
    

    您还使用另一个具有相同 ID 和附加参数的函数,它可以工作,但开发人员会感到困惑。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-16
      • 1970-01-01
      • 1970-01-01
      • 2016-05-24
      • 2011-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多