Base-class pointer, accessing object from derived class

This is a discussion on Base-class pointer, accessing object from derived class within the C++ Programming forums, part of the General Programming Boards category; Hello, I'd like to thank everyone that helped me out last time when I was having class issues - I've ...

  1. #1
    Confused
    Join Date
    Nov 2002
    Location
    Warwick, UK
    Posts
    209

    Base-class pointer, accessing object from derived class

    Hello,

    I'd like to thank everyone that helped me out last time when I was having class issues - I've taken your recommendations on board and rewritten my code. Here's an explanation of my problem :

    I'm writing a simulation programme that incorporates a doubly-linked list as a way to control "pieces" on a "gameboard". I've now written a class to handle my nodes, and a class to handle the list of nodes itself.

    My class Node is fairly basic, and manages what a node should contain. The code is as follows :

    Code:
    class Node
    {
        public:
            Node *next;
            Node *prev;
            Node(); // CONSTRUCTOR
            void move();
            void place();
            int readx();
            int ready();
            int type;
    
        protected:
            int x;
            int y;
    };
    
    
    
    
    
    
    
    
    // Constructor
    Node::Node()
    {
        next = NULL;
        prev = NULL;
        place();
        x = 1;
        y = 1;
        type = NODE; // NODE is an enum, at the moment NODE == 0
    }
    
    
    
    
    
    
    int Node::readx()
    {
        return x;
    }
    
    
    
    int Node::ready()
    {
        return y;
    }
    
    
    
    
    // Node Movement
    void Node::move()
    {
        positions[x][y].presence[type] = FALSE; // Remove this piece from its current place on the board
    
        switch((rand() % 8) + 1) // Generate a random direction
        {
            case 1:
                x += 1;
                break;
            case 2:
                x += 1;
                y += 1;
                break;
            case 3:
                y += 1;
                break;
            case 4:
                y += 1;
                x -= 1;
                break;
            case 5:
                x -= 1;
                break;
            case 6:
                x -= 1;
                y -= 1;
                break;
            case 7:
                y -= 1;
                break;
            case 8:
                x +=1 ;
                y -= 1;
                break;
        }
    
        // Cyclic board - pieces "wrap around" the edges of the board
        if(x < 1) x = BOARDMAX;
        if(x > BOARDMAX) x = 1;
    
        if(y < 1) y = BOARDMAX;
        if(y > BOARDMAX) y = 1;
    
    
        positions[x][y].presence[type] = TRUE; // Place this piece on the board
    
    
    
        // DEBUG
        cout << "Moved.\n";
        // Used to count that the correct number of nodes are being moved at first
    }
    
    
    
    
    
    
    // Set initial, random position on board
    void Node::place()
    {
        x = (rand() % BOARDMAX) + 1;
        y = (rand() % BOARDMAX) + 1;
        positions[x][y].presence[type] = TRUE;
    }


    To clarify certain aspects of that, namely the positions.presence, here's that structure :

    Code:
    struct contents // Possible "pieces"
    {
        bool presence[TOTAL_TYPES];
    };
    
    contents positions[BOARDMAX][BOARDMAX]; // Game position grid
    with TOTAL_TYPES being the last of my ENUM ( just an int ).




    I have a class, called Mortal, which derives from Node. It adds a boolean, like so :

    Code:
    class Mortal : public Node
    {
        public:
            bool death;
            Mortal();
    };
    
    
    
    
    
    // Derived classes don't inherit a constructor, but is executed anyway, so we need a constructor anyway :
    // Constructor
    Mortal::Mortal()
    {
        type = MORTAL;
        death = FALSE;
    }




    My problem comes when I try to use a pointer to a node object, Node * conductor ( my iterator, essentially ) to access my boolean, "death".

    Code:
    if(mortalslist.conductor->death) mortalslist.remove();
    where mortalslist is an object of type List, with Mortals as nodes.


    My error is :

    Code:
    'class Node' has no member named 'death'

    Is there a way around this ? I don't want to create a pointer of type Mortal, as this will break all of the polymorphism I've worked into the code, and will make future expandability very poor. Can it be typecast ? Is there another, better solution ?


    Thanks very much once again,
    Quentin

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    I would think you wouldn't want polymorphism to handle this -- there isn't a death variable in the base class, so if you're trying to access it, you had bloody well be sure that you have a Mortal object and not just a Node. In other words, a dynamic_cast may very well save you from yourself here.

  3. #3
    Confused
    Join Date
    Nov 2002
    Location
    Warwick, UK
    Posts
    209
    Could you show me the syntax ? I've tried dynamic_cast on the line above, and couldn't get it to work. Namely,

    Code:
    if(mortalslist.dynamic_cast<Mortal*>(conductor)->death) mortalslist.remove();
    gives me

    Code:
    expected unqualified-id before "dynamic_cast"
    expected ')' before "dynamic_cast"

    Polymorphism isn't handling this specifically, but I have other node-types which need to inherit Node, and will each have their own additional variables and behaviours. I want to be able to use my iterator pointer in each case, and not have to write a special one for each ( again, expandability ).

    Thanks again,
    Quentin

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    I would think it would have to be
    Code:
    dynamic_cast<Mortal*>(mortalslist.conductor)->death
    And dynamic_cast is going to throw if mortalslist.conductor doesn't point to a Mortal, so be sure or wrap it in an if or try/catch or whatever. EDIT: I'm wrong, it doesn't throw on a pointer, it gives you a NULL. So check that it succeeds.
    Last edited by tabstop; 09-27-2008 at 06:53 PM.

  5. #5
    Confused
    Join Date
    Nov 2002
    Location
    Warwick, UK
    Posts
    209
    Interesting.

    [code]error: cannot dynamic_cast `mortalslist.List::conductor' (of type `class Node*') to type `class Mortal*' (source type is not polymorphic)[/error]

    Using a reinterpret_cast, I was able to get it to work - I apparently needed a virtual function which I don't have, to use dynamic_cast.

    Now though, I get a seg fault... The line
    Code:
    positions[x][y].presence[type] = TRUE;
    which is called when I initialise my list ( make a bunch of nodes and tie them together ) causes a seg fault. I'm not sure why, it's not accessing memory it shouldn't - I think.

  6. #6
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    Remember that arrays go from 0 to n-1, not 1 to n.

    And yes, you would need a virtual function I suppose to be considered polymorphic. You will need virtual if you ever write, say, Mortal::Place() to do things that Node::Place() can't, or similar.

  7. #7
    Confused
    Join Date
    Nov 2002
    Location
    Warwick, UK
    Posts
    209
    int type, that is taken as an argument under positions.presence, is part of an ENUM, and hence starts at zero, so there's no problem with it being invalid in the array.

  8. #8
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    I don't care about type; you explicitly go out of bounds with your x and your y.

  9. #9
    Confused
    Join Date
    Nov 2002
    Location
    Warwick, UK
    Posts
    209
    How so ? They're part of Node, and so, part of Mortal.

  10. #10
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    Let's say, just for fun, that your BOARDMAX is 8, and that we manage to get x and y to be 8 as well. You then try to access positions[8][8], which just simply does not exist anywhere in this universe. You have positions[0][0] through positions[7][7], which is in fact an 8x8 grid like you want, and you will have to get used to the fact that arrays are indexed from 0 and end at n-1.

  11. #11
    Confused
    Join Date
    Nov 2002
    Location
    Warwick, UK
    Posts
    209
    Ah, I see where I went wrong there. I've now fixed that, but still get a segfault in the same place.

  12. #12
    Chinese pâté foxman's Avatar
    Join Date
    Jul 2007
    Location
    Canada
    Posts
    404
    If you intend to use your Node class polymorphically, you should have at least a virtual destructor.
    I hate real numbers.

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    And actually, now that I read your program in the order that it executes, type is NOT initialized when you call place(). So who knows what's in there.

    And also, do you realize that you end up placing all your pieces at (1,1)? (Well, you set a random place true in the positions grid, but then you set x and y to 1 afterward.)

  14. #14
    Confused
    Join Date
    Nov 2002
    Location
    Warwick, UK
    Posts
    209
    tabstop - type is initialised in the constructor of the node, so I know exactly what's in there. In a Mortal, it's 2. In a Node, it's 0.

    And yes, I place my pieces at 1,1, again in the constructor. Then, place() is called, giving them random positions...

  15. #15
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    Quote Originally Posted by Korhedron View Post
    tabstop - type is initialised in the constructor of the node, so I know exactly what's in there. In a Mortal, it's 2. In a Node, it's 0.

    And yes, I place my pieces at 1,1, again in the constructor. Then, place() is called, giving them random positions...
    You do realize that program control starts at the first line (the "top") and goes to the last (the "bottom") and not the other way around, right?

    Edit: Oh, and also base is constructed before derived, so even if you fix that, when you construct a Mortal place() will think type == NODE, so you may need to change that in the Mortal constructor.
    Last edited by tabstop; 09-27-2008 at 07:56 PM.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. sorting number
    By Leslie in forum C Programming
    Replies: 8
    Last Post: 05-20-2009, 04:23 AM
  2. Virtual base class
    By George2 in forum C++ Programming
    Replies: 7
    Last Post: 03-14-2008, 07:45 AM
  3. deriving classes
    By l2u in forum C++ Programming
    Replies: 12
    Last Post: 01-15-2007, 04:01 PM
  4. Instantiating a derived class from a Base class
    By kwoky in forum C++ Programming
    Replies: 2
    Last Post: 07-21-2003, 01:33 AM
  5. Exporting Object Hierarchies from a DLL
    By andy668 in forum C++ Programming
    Replies: 0
    Last Post: 10-20-2001, 01:26 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21