Thread: Wrong member function. Is this the slice problem?

  1. #1
    Registered User
    Join Date
    Mar 2012
    Posts
    6

    Wrong member function. Is this the slice problem?

    Hello. I am having a problem with a program. I have a bunch of classes all derived from the same base class. I want to loop through a vector of objects, calling a function in each. The problem is that it doesn't matter which class the objects are, only the function defined in the base class is called.

    I simplified the code as far as possible to replicate the problem. As you see, I would like a mix of numbers 1,2,3 as the output, however using the vector the only number output is 1. Here is a copy of the output by the way:

    base->num() : 1
    a->num() : 2
    b->num() : 3
    (*it)->num() : 1
    (*it)->num() : 1
    (*it)->num() : 1

    I suspect this is the "slice" problem, because the vector is defined with pointers to the base class so it uses the base class functions? The question is how to get around it? How can I loop through a vector of objects sharing the same base class but calling each by their correct member functions?

    I am thankful for any help.

    Code:
    #include <iostream>
    #include <vector>
    
    class Base
    {
    public:
        int num() { return 1;}
    };
    
    class HeirA : public Base
    {
    public:
        int num() { return 2;}
    };
    
    class HeirB : public Base
    {
    public:
        int num() { return 3;}
    };
    
    int main(int argc, char** argv)
    {
        Base* base = new Base();
        HeirA* a = new HeirA();
        HeirB* b = new HeirB();
    
        // Explicitly specifying each object.
        std::cout << "base->num() : " << base->num() << std::endl;
        std::cout << "a->num() : " << a->num() << std::endl;
        std::cout << "b->num() : " << b->num() << std::endl;
    
        // Looping through a vector.
        std::vector<Base*> list;
        list.push_back(base);
        list.push_back(a);
        list.push_back(b);
        std::vector<Base*>::iterator it = list.begin();
        while (it != list.end())
        {
            std::cout << "(*it)->num() : " << (*it)->num() << std::endl;
            ++it;
        }
    }

  2. #2
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    937
    It looks like you want to declare Base::num() virtual. This way, regardless of whether you call num() via a base pointer/reference or a derived base/reference, it will use the most derived implementation at runtime.
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    This is not slicing.

    The code that "explicitly specifies each object" is demonstrating effects of the hiding rule: in the context of both derived classes, Base::num() is hidden. The code that is iterating over the vector is using static dispatch (always calling the Base::num()) since that function is non-virtual.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  4. #4
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    This would cause slicing
    Code:
    #include <iostream>
    #include <vector>
     
    class Base
    {
    public:
        virtual int num() { return 1;}
    };
     
    class HeirA : public Base
    {
    public:
        virtual int num() { return 2;}
    };
     
    class HeirB : public Base
    {
    public:
        virtual int num() { return 3;}
    };
     
    int main(int argc, char** argv)
    {
        Base base;
        HeirA a;
        HeirB b;
     
        // Looping through a vector.
        std::vector<Base> list;
        list.push_back(base);
        list.push_back(a);
        list.push_back(b);
        std::vector<Base>::iterator it = list.begin();
        while (it != list.end())
        {
            std::cout << "(*it).num() : " << (*it).num() << std::endl;
            ++it;
        }
    }
    Kurt

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    You also want to look at smart pointers, std::unique_ptr and std::shared_ptr especially.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Registered User
    Join Date
    Mar 2012
    Posts
    6
    Ah, virtual! I had completely forgotten about that. Thank you all.

    Quote Originally Posted by Elysia View Post
    You also want to look at smart pointers, std::unique_ptr and std::shared_ptr especially.
    Yes, I suppose I should do that.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. class member function problem
    By IDK_22 in forum C++ Programming
    Replies: 4
    Last Post: 03-11-2009, 07:10 AM
  2. problem threading a member function
    By Syneris in forum C++ Programming
    Replies: 10
    Last Post: 12-31-2008, 07:26 PM
  3. Bjarne's member function binding sample is wrong?
    By George2 in forum C++ Programming
    Replies: 9
    Last Post: 03-11-2008, 04:05 AM
  4. non-class member function problem
    By geek@02 in forum Windows Programming
    Replies: 9
    Last Post: 12-16-2007, 10:50 PM
  5. problem of input in member function of class
    By Roy01 in forum C++ Programming
    Replies: 5
    Last Post: 11-27-2006, 10:27 AM