2

Given the following code:

class Base {
public:
    virtual void Test() {
        cout << "Not Overridden" << endl;
    }
};

class Derived : public Base {
public:
    void Test() override {
        cout << "Overridden" << endl;
    }
};

int main() {
    Base o = Derived();
    o.Test();
    return 0;
}

Someone like me who is from a Java background, expects the compiler to output Overridden but surprisingly the output is exactly the otherwise.

If this is a normal behavior, then what's the point of inheritance in C++ at all?

What is that I am missing?

anastaciu
  • 23,467
  • 7
  • 28
  • 53
Arnold Zahrneinder
  • 4,788
  • 10
  • 40
  • 76

2 Answers2

3

Yes, it's normal behavior, polymorphism only works with pointers and references.

With raw pointer:

int main() {
    Base* o = new Derived();
    o->Test();
    delete o; //when done with using it delete it from memory
    //...
}

An alternative to this memory management would be to use smart pointers.

With smart pointer:

int main() {
    unique_ptr<Base> o(new Derived); // automatic memory management
    o->Test();
    //...
}

With reference:

int main() {
    Derived d;
    Base& o = d;
    o.Test();
    //...
}

This is something you need to be careful with, when the block where Derived object was declared goes out of scope, the reference will be rendered useless, for example, if you return it from a function.

Output:

Overridden

Some threads on the site explain why this is so, like this one.

The way you have it leads to object slicing.

You'll also want to add a virtual destructor to your base class.

anastaciu
  • 23,467
  • 7
  • 28
  • 53
  • It was probably done that way because C did it that way, i.e. both languages pass by value by default and require you to opt-in to passing by reference. Arguably that makes as much if not more sense as passing by reference by default and having to opt-in to passing values, or having no way to do so (like certain other languages!) – underscore_d Jun 20 '20 at 11:44
2
Base o = Derived();

o above is an object – a Base object – not a Derived one. The o object is created from a Derived object by means of object slicing, but o is still a Base object. There is no dynamic dispatch here, so o.Test() results in Base::Test() being called.

Instead, if you declare o as a Base pointer that refers to the Derived object you create:

Base* o = new Derived();
o->Test();

In this case, o is a pointer to an object – as opposed to an object – and dynamic dispatch takes effect: Even though o is a pointer to a Base object, it is bound to a Derived object, so o->Test() results in Derived::Test() being called this time due to dynamic dispatch.

Analogously if o is a reference to Base instead of a pointer.

JFMR
  • 23,265
  • 4
  • 52
  • 76
  • 1
    Since I upvoted your answer I needed to make that correction, I hope you don't mind. – anastaciu Jun 21 '20 at 11:14
  • 1
    @anastaciu Thank you very much for the correction. I just removed the relevant code from `main()` so that I don't need to add the statement `delete o;` as well. I think it's clearer like this because it's more concise. – JFMR Jun 21 '20 at 11:19