0

I am making a chess game and have an error where the override method in the child class is not always overriding the parent class.

More specifically on temp2.setgetMoves(generation) but only on the second time it is used for a piece. The error occurs because I have used inheritance with a virtual method in the parent and an override method in the child classes. For example in the parent class the method is:

abstract class Piece
{
    String pieceType;
    int pieceVal;
    Panel piecePanel;


    public Piece(String type, int value, Panel image)
    {

        image.BackgroundImage = (Image)(Properties.Resources.ResourceManager.GetObject(type));

        pieceType = type;
        pieceVal = value;
        piecePanel = image;
    }

    public abstract List<Panel> setgetMoves(BoardGen board);

    public virtual List<Panel> getMoves()
    {
        return null;
    }

    public String getType()
    {
        return pieceType;
    }

    public void setPanel(Panel newPanel)
    {
        piecePanel = newPanel;
    }

    public Panel getPanel()
    {
        return piecePanel;
    }

    public int getValue()
    {
        return pieceVal;
    }
}

and in the child class (as an example this is an uncomplete pawn class, it does not have taking pieces or the en passant or promotion yet but it is all I have gotten around to so far) the code is:

class Pawn : Piece
{
    public List<Panel> possibleMoves;
    public Pawn(string type, int value, Panel image) : base(type, value, image)
    {

    }

    public override List<Panel> setgetMoves(BoardGen board)
    {
        possibleMoves = new List<Panel>();
        foreach (Panel x in board.getPanels())
        {
            if (this.getType().Substring(0, 1).Equals("W"))
            {
                if (this.getPanel().Location.Y == 240 && ((x.Location.Y == this.getPanel().Location.Y - 40) || (x.Location.Y == this.getPanel().Location.Y - 80)) && (x.Location.X == this.getPanel().Location.X))
                {
                    possibleMoves.Add(x);
                }

                else if((x.Location.Y == (this.getPanel().Location.Y - 40)) && (x.Location.X == this.getPanel().Location.X))
                {

                    possibleMoves.Add(x);
                }
            }
            else if (this.getType().Substring(0,1).Equals("B"))
            {
                if (this.getPanel().Location.Y == 40 && ((x.Location.Y == this.getPanel().Location.Y + 40) || (x.Location.Y == this.getPanel().Location.Y + 80)) && (x.Location.X == this.getPanel().Location.X))
                {
                    possibleMoves.Add(x);
                }
                else if (x.Location.Y == this.getPanel().Location.Y + 40 && (x.Location.X == this.getPanel().Location.X))
                {
                    possibleMoves.Add(x);
                }
            }
        }
        return possibleMoves;
    }

    public override List<Panel> getMoves()
    {
        return possibleMoves;
    }

Any help with why it may not override the second time would be really helpful. Thank you.

space482
  • 29
  • 7
  • I'm not sure why this was linked as duplicate to an unrelated issue. I guess Plutonix, Camilio and Uwe didn't read the question? The code you provided isn't sufficient to point at the error; perhaps you can make the base class and the setgetMoves-method abstract, and see if you get a compiler error. Just a suggestion, can't guarantee it helps finding the error. – EventHorizon Apr 29 '18 at 18:15
  • Thank you for your reply. After adding in the abstract base class abstract, I have an error before the code can compile. It says that I may not create an instance of the abstract class 'Piece'. Any idea how I may fix this? – space482 Apr 29 '18 at 18:28
  • That's exactly what I hoped for :) You only want to create instances of the child classes. If you need instances of the base-class as well, you'll have to check for null values returned from the method in your base class. Ninja edit: Panel panel = new ChildPanel() is valid if ChildPanel inherits from Panel. – EventHorizon Apr 29 '18 at 18:30
  • I do need to create instances of the base class, but I didn't fully understand what you said after that? Sorry – space482 Apr 29 '18 at 18:33
  • I use the line "Piece temp3 = new Piece(temp2.getType(), temp2.getValue(), panel);" where I am unsure what the child class will be, other than in a string. Is there a way for me to use the string as the class type (other than going through a lot of if statements? – space482 Apr 29 '18 at 18:37
  • The reason your question got closed is because you acted like you don't know why there's a null reference exception. You *do* know, it's because that function returns `null`. Your real question seems to be about why the base class function is getting called in the first place. Edit your question to focus on your actual problem, and I or another gold badge user will be happy to reopen it. – Ben Voigt Apr 29 '18 at 18:37
  • In particular, we need to know what classes you have, what the inheritance relationships are, and how you create objects of those class types. – Ben Voigt Apr 29 '18 at 18:39
  • Thanks Ben :). Trying to help a beginner here. The safest to begin with is to use if-s, space482, but if you feel fancy take a look at the Activator class. – EventHorizon Apr 29 '18 at 18:39
  • I have edited the question – space482 Apr 29 '18 at 18:40
  • @space482: The title is much better, now please improve the rest (the comment I left while you were editing should provide some guidance). Also, when the error happens, put a watch expression on `temp2.GetType()` -- seeing what the runtime type of the object `temp2` points at may show you your mistake. – Ben Voigt Apr 29 '18 at 18:43
  • 1
    Ah I just properly read your comment about `Piece temp3 = new Piece(temp2.getType(), temp2.getValue(), panel);` That is the problem, you aren't creating an object of the right type. EventHorizon's mention of `Activator` is an answer to the general problem of "create an object when the name of its type is found in a string", but I want you to take one step back and re-think why you are even doing this. – Ben Voigt Apr 29 '18 at 18:46
  • 1
    In Chess, pieces should only get created at two times: When the board is first set up, and when a pawn reaches the far end and is promoted (typically to a queen, but rook, knight, bishop are also possible and sometimes necessary to prevent a draw). At all other times, pieces are moved or destroyed (captured) but moves don't create new pieces. – Ben Voigt Apr 29 '18 at 18:48
  • Perhaps you can get rid of that problem line of code by moving the piece that already exists instead of making a new one. – Ben Voigt Apr 29 '18 at 18:48
  • I see about not creating an object of the right type now, but what do you mean by why am I doing this? Apologies the site just updated so I only just got your new comments – space482 Apr 29 '18 at 18:52
  • Instead of that `Piece temp3 = new Piece(temp2.getType(), temp2.getValue(), panel);` how about something like `temp2.changeLocation(panel)` that reflects what is going on in the game (movement)? – Ben Voigt Apr 29 '18 at 18:55
  • How would I go about moving the piece that already exists? Is there a way I can update the panel of a piece that exists? I have a get and set panel function in my Piece class but that doesn't actually change anything in the interface – space482 Apr 29 '18 at 18:56
  • @space482: Does `Piece` add itself to the panel, maybe with `panel.Controls.Add(this);`? You can try setting `this.Parent = newpanel;` or `oldpanel.Controls.Remove(this); newpanel.Controls.Add(this);` or something like that, to move it on screen to match the movement in the internal data. – Ben Voigt Apr 29 '18 at 18:57
  • My pieces act as essentially images. A piece adds itself to a panel by editing the background image of that panel – space482 Apr 29 '18 at 19:03
  • Anyway, I'd like to reopen your question so more people can help you, and do it with proper answers, but the main text of your question still talks too much about the exception you got and not enough about the class hierarchy and the problem you're having with giving the object a matching type. Please consider providing some of the details from comments into the question itself. – Ben Voigt Apr 29 '18 at 19:04
  • Ahh, well then the set panel function in your Piece class could change the background image of the old panel back to blank and put the picture of the piece into the new panel. – Ben Voigt Apr 29 '18 at 19:06
  • I have edited it again, is that better? – space482 Apr 29 '18 at 19:08
  • It's now very clear that it is not just another NullReferenceException -- I've removed the wrong duplicate marking. You might not be done editing if people point out more needed details in comments, but it's about 300% better than it was. – Ben Voigt Apr 29 '18 at 19:17
  • 1
    So I edited everything, I am now updating panels rather than creating new pieces and it is working nicely. Thank you!! – space482 Apr 29 '18 at 19:24

1 Answers1

1

Since the back-and-forth comments have uncovered a possible X-Y problem, I wanted to help fix your setPanel() function. Hopefully that allows you to reuse your existing objects of correct type and avoid making brand new ones that don't have the right type (and therefore don't find the correct override).

Your constructor makes a change to the BackgroundImage property of its Panel argument:

image.BackgroundImage = (Image)(Properties.Resources.ResourceManager.GetObject(type));

Therefore, when we change the panel, we should undo our prior interaction with the original panel, and redo it for the new panel:

public void setPanel(Panel newPanel)
{
    newPanel.BackgroundImage = piecePanel.BackgroundImage;
    piecePanel.BackgroundImage = null;
    piecePanel = newPanel;
}
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720