views:

101

answers:

8

I have a base class pointer pointing to derived class object. I am calling foo() function by using two different ways as mentioned below in Code. I want to know why in first case Derived:foo() is getting called.

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;
    }
+3  A: 

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.

bdonlan
Worth describing slicing.
Martin York
A: 

Polymorphism works on references (the result of dereferencing a pointer) just as it does on pointers.

Ben Voigt
A: 

What do yo mean by "as it has already been dereferenced "?

The base class pointer obj is pointing to derived class object and since you have declared the function foo() virtual the derived class foo() will be called.

ckv
+1  A: 

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.

Peter Milley
A: 

(It is rather strange question. I would rather expect someone ask why in the second case Derived::foo is not called.)

In C++ language, which version of virtual function is called is completely independent of what has and what has not been "dereferenced". Dereferencing makes no difference whatsoever. The only thing that matters is the dynamic type of the object used in the call.

In the first case Derived::foo is called because the dynamic type of the *obj object is Derived.

In the second case the dynamic type of obj1 is Base, so the Base::foo is called.

In other words, everything works as expected. Which makes one wonder wat made you ask your question. What made you to expect something different?

AndreyT
+1  A: 

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:

http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c

ryaner
+1  A: 

In first case the derived version of foo() will be called due to the obvious reasons explained above. Just to add more reasoning - the *(Obj).func() is synonymous to Obj->func().

In second case a new object of class Base is being instantiated through the copy constructor and since its wholly a base class object it will call the base class version of foo().

Hemant
+8  A: 
// 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();
sbi