Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Virtual function calling using dereference object

I have a base class pointer pointing to a derived class object. I am calling foo() function by using two different ways in the code below. Why does Derived::foo() get called in the first case? Shouldn't (*obj).foo() call Base::foo() function as it has already been dereferenced?

    class Base
    {
    public:
        Base() {}
        virtual void foo() { std::cout << "Base::foo() called" << std::endl; }
        virtual ~Base() {};
    };

    class Derived: public Base
    {
    public:
        Derived() : Base() {}
        virtual void foo() {  std::cout << "Derived::foo() called" << std::endl; }
        virtual ~Derived() {};
    };

    int main() {
        Base* obj = new Derived();
   // SCENARIO 1
        (*obj).foo();
// SCENARIO 2
        Base obj1 = *obj;
        obj1.foo();

        return 0;
    }
like image 585
Pardeep Avatar asked Jun 21 '10 05:06

Pardeep


4 Answers

// SCENARIO 1
(*obj).foo();

Note that

  1. obj is a misnomer here, since it doesn't refer to an object, but to a pointer,
  2. (*ptr).foo() is just a roundabout way to do ptr->foo().

*ptr doesn't result in an object, but in a reference Base& to the object. And a virtual function call through a reference is subject to dynamic dispatch, just as such a call through a pointer.

// SCENARIO 2
Base obj1 = *ptr;
obj1.foo();

What you do here is you create a totally new object through slicing: it just has the base class parts of *ptr. What you want instead is this:

Base& ref = *ptr;
ref.foo();
like image 82
sbi Avatar answered Nov 15 '22 09:11

sbi


Scenario 2 creates an entirely new object of type Base. As such, when we do obj1.foo(), the object isn't Derived at all; there's no way we'll call the Derived function.

In scenario 1, however, the object is, in truth, an instance of Derived, which we're accessing through a Base pointer. This is exactly the situation virtual functions are designed for; the derived class's implementation is used.

like image 22
bdonlan Avatar answered Nov 15 '22 09:11

bdonlan


It helps if you think a little bit about the implementation. In the second scenario you're actually creating a new object of type Base which will come with a new virtual function table. But in the first scenario *obj will "point to", or rather reference, an object which still has the virtual function table of an object of type Derived.

like image 43
Peter Milley Avatar answered Nov 15 '22 08:11

Peter Milley


As an addition to other answers.

The technical term for what is happening in your Scenario 2 is object slicing.

Here's the wikipedia entry:

http://en.wikipedia.org/wiki/Object_slicing

And here's another question on stackoverflow on object slicing:

What is object slicing?

like image 24
ryaner Avatar answered Nov 15 '22 08:11

ryaner