Thread: Virtual Method question...

  1. #1
    Registered User
    Join Date
    Aug 2007
    Posts
    81

    Virtual Method question...

    Hello.

    For some reason my virtual base method is being called on a pointer to a derived object that overrides the virtual base method. And I don't understand why... Here's some psuedo code that illustrates the situation I'm in:

    Code:
    class Base
    {
         virtual void doSomething();
    }
    
    class Derived : public Base
    {
    
         void doSomething();
    }
    
    int main()
    {
         Base* p;  
         List<Base*>  list;
         list.add(new Derived()); 
         p = list.pop();
         p->doSomething();   // For some reason this is calling Base::doSomething()
    
         return 0;  
    }
    Based on the above scenario, does anyone see why p->doSomething() calls the Base method? Or any guesses as to what I'm doing wrong?

  2. #2
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    Post the real code - that won't compile as doSomething is private in base and derived, so you can't call it on p in main().

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I suspect your example code is not your real code, since it won't compile.

    I modified it into this [using STL classes, since I don't know that your List class actually does], and it works fine:
    Code:
    #include <iostream>
    #include <list>
    
    class Base
    {
    public:
      virtual void doSomething() { std::cout << "Base" << std::endl; }
    };
    
    class Derived : public Base
    {
    public:
      virtual void doSomething() { std::cout << "Derived" << std::endl; }
    };
    
    int main()
    {
         Base* p;  
         std::list<Base*>  lst;
         lst.push_back(new Derived()); 
         p = lst.back();
         p->doSomething();   // For some reason this is calling Base::doSomething()
    
         return 0;  
    }
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    Registered User
    Join Date
    Aug 2007
    Posts
    81
    Okay, thanks,

    Code:
       RTSConnection* conn = RTSConnection::getServerConnection();
       for (U32 i = 0; i < mObjectList.size(); i++)
       {
          SceneObject* unit = listOfSceneObjects[i]; 
    
          if ( unit->getTeam() == conn->getTeam() )    // unit->getTeam() is calling virtual S32 SceneObject::getTeam() for some reason, meanwhile
                                                                                //  listOfSceneObjects[i] is a pointer to a RTSUnit, and an RTSUnit overrides getTeam().  Also note RTSUnit                    
                                                                                //derives (eventually) from SceneObject...  
             continue;
    
           etc....
    I don't think that's any more clear, but it is what you asked for :P
    Last edited by keira; 05-22-2008 at 11:41 AM.

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Well, of course, we'd need to see the REST of the code so that it can be compiled. Your simple example isn't the same as "the minimal complete example that compiles and demonstrates the problem".

    In your process to whittle down your code into that, you may well find the actual problem.

    Certainly, there's nothing in your code-snippet that is directly wrong, as far as I can see. But it's also very different from the code you originally posted, and the problem is very likely in a different portion of code.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    Well, it's hard to tell without seeing what kind of objects are put into listOfSceneObjects.

  7. #7
    Registered User
    Join Date
    Aug 2007
    Posts
    81
    My gut tells me it has something to do with this:

    Code:
    void addObject(SceneObject* unit)
    {
          listOfSceneObjects.add(unit);
    }
    that shows how the listOfSceneObjects gets populated in the first place. listOfSceneObjects is actually a SimSet which is a Set of SimObjects and everything else in the code derives from SimObject.

    So if I add an RTSUnit* unit;
    like this:
    addObject(unit);

    Does this somehow strip the v-table out of unit or what lol


    EDIT: I cannot provide compileable code as it is 100's of thousands of lines long. But what I have shown is really all that is going on. I just don't understand it
    Last edited by keira; 05-22-2008 at 11:50 AM.

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I'm assuming RTSUnit is a derived class based on SceneObject (or it shouldn't compile). I don't see anything wrong with that code either.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    Aug 2007
    Posts
    81
    Yes, it's very strange, there must be something else going on as you alluded earlier.

    Also, the reason I don't simply

    Code:
    void VisManager::processClient()
    {
       if (!mDirty || !gFogOfWarIsOn)
          return;
       PROFILE_START(VisManager_Process_Client);
    
       RTSConnection* conn = RTSConnection::getServerConnection();
       for (U32 i = 0; i < mObjectList.size(); i++)
       {
          RTSUnit* unit = dynamic_cast<RTSUnit*>(mObjectList[i]);
    
    		if ( !unit )
    			continue;  // do nothing if it is not a RTSUnit.
    
          if ( unit->getTeam() == conn->getTeam() )
             continue;
    
          etc...
    }
    Is because I have other types of "units" that I would like to call unit::getTeam() on. And duplicating code and performing multiple dynamic_casts is too hacky for my taste.

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Yeah, that would be an ugly hack and not the right solution.

    You may want to check your vtable in the debugger [most debuggers will at least show the address of the vtable].

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    The larch
    Join Date
    May 2006
    Posts
    3,573
    If listOfSceneObjects is a Set<SimObject*> (why!?) and SceneObject derives from SimObject, why does this line compile?
    Code:
    SceneObject* unit = listOfSceneObjects[i];
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    that shows how the listOfSceneObjects gets populated in the first place. listOfSceneObjects is actually a SimSet which is a Set of SimObjects and everything else in the code derives from SimObject.
    Is listOfSceneObjects actually a Set of (smart) pointers to SimObjects? If it really stored SimObjects instead of pointers (or references, but that's rare for a container), type slicing occurs, so all you have are SimObjects with the subtype information lost.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User
    Join Date
    Aug 2007
    Posts
    81
    Delving deeper into SimSet ( what listOfSimObjects is )

    Code:
    template<class T> inline void VectorPtr<T>::push_back(const T& x)
    {
       Parent::push_back((Parent::const_reference)x);
    }
    Code:
    template<class T> inline void Vector<T>::push_back(const T& x)
    {
       increment();
       mArray[mElementCount - 1] = x;
    }
    So it appears this is the result of type slicing after all. thanks laserlight!
    Last edited by keira; 05-22-2008 at 12:40 PM.

  14. #14
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Ok, so is it this cast?
    Code:
    Parent::push_back((Parent::const_reference)x);
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  15. #15
    Registered User
    Join Date
    Aug 2007
    Posts
    81
    I think I misunderstood laserlight. If I can dynamic_cast it fine, doesn't that rule out type slicing?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. virtual page question
    By uscuba2 in forum Tech Board
    Replies: 5
    Last Post: 06-03-2009, 10:10 AM
  2. Need help on pure virtual method
    By wanex in forum C++ Programming
    Replies: 9
    Last Post: 03-25-2006, 07:51 AM
  3. Microsoft Virtual PC question
    By Lionel in forum Windows Programming
    Replies: 2
    Last Post: 07-24-2005, 11:09 PM
  4. C++ XML Class
    By edwardtisdale in forum C++ Programming
    Replies: 0
    Last Post: 12-10-2001, 11:14 PM
  5. Exporting Object Hierarchies from a DLL
    By andy668 in forum C++ Programming
    Replies: 0
    Last Post: 10-20-2001, 01:26 PM