1
class A
{
    public:
        virtual void Print()
        {
            cout<<"A"<<endl;
            Print(1);
        }
        void Print(int n)
        {
            cout<<"A - "<<n<<endl;
        }
};


class B: public A
{
    public:
        void Print()
        {
            cout<<"B"<<endl;
            Print(1);
        }
        void Print(int n)
        {
            cout<<"B - "<<n<<endl;
        }
};

class C:public B
{
    public:
        void Print()
        {
            cout<<"C"<<endl;
            Print(1);
        }
        void Print(int n)
        {
            cout<<"C - "<<n<<endl;
        }
};

int main()
{
    A *p=new B;
    p->Print();
    ((C*)p)->Print(9);
}

Above is my code. The result I got is :

B
B - 1
C - 9

My question is: why the object B can call a function member of class C (its child)? How can object B contain code of class C? I just think it will call class B member function. So the result should be:

B
B - 1
B - 9

Please help me understand what is going on.

paddy
  • 60,864
  • 6
  • 61
  • 103
Juley J
  • 11
  • 2
  • 1
    `((C*)p)` is just undefined behavior. You're telling the compiler to override what it thinks it knows about `p`, it's really pointing to a `C`. But it isn't. So, strictly speaking, _any_ output is acceptable. But because `C::Print(int)` doesn't actually rely on any from a `C` instance to achieve its effect, the compiler is able to create the results of "what would happen if `p` really did point to a `C` object". – Nathan Pierson Nov 02 '21 at 04:05

1 Answers1

2

To begin with, Print(int) is not a virtual function, whereas Print() is. So when you explicitly invoke C::Print(int) it does not do a lookup of that function in the virtual table. Instead, it just calls C::Print(int).

The weird thing is that you have cast something to C that is not a C object. This is undefined behavior. Indeed, dynamic_cast<C*>(p) would return nullptr. What you are doing here is fundamentally incorrect.

You are welcome to call that function without the cast:

p->Print(9);

But because it's not a virtual function it will output "A - 9", as the type of p is A*.

If you only want to call that if it's a C-derived type, then you can safely do it like this:

if (C* pc = dynamic_cast<C*>(p))
    pc->Print(9);
paddy
  • 60,864
  • 6
  • 61
  • 103
  • I have tried it with ```dynamic_cast(p)``` and it still give me the result : ```B B - 1 C - 9``` , I expected it would be error or weird result, but it doesn't. – Juley J Nov 02 '21 at 14:30
  • You're misunderstanding. Do you see how my answer _null-tests_ the dynamic cast? If you don't do this, and `p` is _not_ derived from `C`, then the dynamic-cast will return `nullptr`. So what you're describing is the same issue (undefined behavior) because you're essentially doing `((C*)nullptr)->Print(9);` ... conversely, if you _do_ test it as shown in my example then you won't call the function at all. – paddy Nov 03 '21 at 01:52
  • Oh, I have already understood it. Thank you very much @paddy – Juley J Nov 14 '21 at 13:56