3

In the below c++ code using virtual functions

#include<iostream>
using namespace std;
class Base{
    public:
    virtual void fun(){
        cout << "Base::fun()called \n";
    }

};

class Child : public Base {
    public:
    void fun() {
        cout << "Child::fun() called\n";
    }

    void door(){
        cout << "Child::door() called \n";
    }
};


int main(){

    Base *base_ptr = new Child();
    base_ptr->fun();
    return 0;
}

How can I invoke door function using base_ptr? This question was asked in an interview. I was wondering whether it can be possible

Thanks for your replies

Zaks
  • 668
  • 1
  • 8
  • 30

2 Answers2

6

(Assuming that Base and Child cannot be modified.)

You can use static_cast to convert base_ptr to Child*.

static_cast<Child*>(base_ptr)->door()

This is safe as long as you are sure that base_ptr is actually pointing to a Child instance.


If you don't know what derived instance type base_ptr is pointing to, consider using dynamic_cast:

if(auto child = dynamic_cast<Child*>(base_ptr))
{
    child->door();
}

Unless the compiler manages to aggressively optimize it, dynamic_cast has extra runtime overhead compared to static_cast.

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • 4
    `dynamic_cast` might be more appropriate. – Fred Larson Dec 02 '16 at 17:10
  • 1
    @FredLarson: there's no reason to use `dynamic_cast` in this particular situation. – Vittorio Romeo Dec 02 '16 at 17:10
  • 3
    @VittorioRomeo: You pointed out the reason yourself in your answer, for `static_cast` to be valid, "you must be sure that `base_ptr` is actually pointing to a `Child` instance". `dynamic_cast` allows you to determine whether this is so. – Ben Voigt Dec 02 '16 at 17:11
  • 1
    @BenVoigt: which is always true for the situation presented in the question. I updated the answer in order to make it more general, regardless. – Vittorio Romeo Dec 02 '16 at 17:13
  • 2
    @FredLarson is right, `dynamic_cast` is always the better option simply because it's more resistant to bugs when the code changes and the original assumptions are no longer valid. There are only 2 cases where `static_cast` would be preferred: when there are no virtual functions in the base class, and when you can't afford the overhead of `dynamic_cast` because it's in a tight loop (but you could probably do `dynamic_cast` outside of the loop). – Mark Ransom Dec 02 '16 at 17:18
  • @MarkRansom: it's not. It's the only option when **you do not know the type** of what your base pointer is referring to, and it's a subpar option **when you do know the type**, because it incurs unnecessary run-time cost. – Vittorio Romeo Dec 02 '16 at 17:21
  • @MarkRansom: play around with the example [here on godbolt](https://godbolt.org/g/p0LZy4) and see the difference. – Vittorio Romeo Dec 02 '16 at 17:22
  • 1
    @VittorioRomeo my claim is that the run-time cost is worth the robustness that you gain when making code changes. Most of the time `dynamic_cast` isn't used in an area where it would make a measurable difference. – Mark Ransom Dec 02 '16 at 17:24
  • @MarkRansom: I'd argue that you should protect yourself from code changes by tests and assertions, not by introducing unnecessary run-time overhead. If you know the type, use `static_cast` - maybe [wrap it in a safer interface](https://github.com/SuperV1234/vrm_core/blob/master/include/vrm/core/casts/polymorphic.hpp) like I did, which checks correctness in non-release builds. – Vittorio Romeo Dec 02 '16 at 17:26
  • Not sure when dynamic_cast will become useful can someone modify the code inside main () and help me on this – Zaks Dec 02 '16 at 17:27
  • @Zaks instead of initializing `base_ptr` with `new Child`, initialize it with something that chooses between `Child` and `Base` based on user input or a random number. – Mark Ransom Dec 02 '16 at 17:29
  • @VittorioRomeo so you advocate something like `assert(static_cast(base_ptr) == dynamic_cast(base_ptr)`? I suppose that's valid, but I would consider it unnecessary clutter when `dynamic_cast` by itself is sufficient 99% of the time. It all depends on your priorities I guess. – Mark Ransom Dec 02 '16 at 17:32
  • @MarkRansom: it's not clutter if you wrap it in easy-to-use functions like I did. I can't really find a reason to justify the extra cost of `derived_cast` when you *(as the programmer)* know the type of the pointed object. Using `derived_cast` to **`assert`** correctness in non-release builds is more than reasonable, though. – Vittorio Romeo Dec 02 '16 at 17:35
  • @MarkRansom Is this correct https://godbolt.org/g/bq27lh . I cant able to print the child door when Base is pointing to itself when doing dynamic_cast . – Zaks Dec 02 '16 at 17:43
  • @Zaks yes that's correct. You can't call the child function unless you have an actual child object, otherwise you risk undefined behavior. You *don't* want undefined behavior, it might make demons fly from your nostrils. – Mark Ransom Dec 02 '16 at 17:46
0

Because Base has no door() method, you obviously cannot simply call base_ptr->door().

However, if you know base_ptr is a Child, you can cast it and then call door()

Child* child_ptr = static_cast<Child*>(base_ptr);
child_ptr->door();