1
class A 
{
  public:
     virtual void func() {
      cout<<" func():: in class A"<< endl;
     }
     void func1(){
     cout<<"func1():: in class A";
     }
};

class B: public A {
 public:
 void func() {
      cout<<" func():: in class B"<< endl;
     }
     void func1(){
     cout<<"func1():: in class B";
     }
};

int main()
{
 A a;
 A* pa = &a;
 B* pb = dynamic_cast<B*>(pa);
 pb->func1();
 return 0;
}

Though pb is pointing to an incomplete type and dynamic_cast will return null. But why it is not crashing in this scenario?

add2c
  • 89
  • 1
  • 9
  • 11
    *undefined behavior* is **undefined** *behavior*, there's nothing more to say about it really. – Filip Roséen - refp Mar 09 '15 at 09:51
  • 2
    I can not see any inccomplete type class. – masoud Mar 09 '15 at 09:52
  • If you were trying to access member data in func1 it would certainly crash. – abcthomas Mar 09 '15 at 09:52
  • 1
    An incomplete type is one that has only been declared but not defined. Like `class X;`. What you have is simply dereferencing a null pointer, because the `dynamic_cast` failed and you didn't check the result. – pmr Mar 09 '15 at 10:43

2 Answers2

2

Since func1 in your B class doesn't access any member variables (or virtual functions) it doesn't use the implicit this pointer and therefore, in this case, does not crash.

Note that this is undefined behaviour so it may crash (or do something unexpected) in a different compiler (or compiler version) so don't depend on this behaviour.

Motti
  • 110,860
  • 49
  • 189
  • 262
1

You have a A * that is pointing to an instance of A, not A * that is actually pointing to an instance of B. That is why dynamic_cast returns a null pointer of type B *, it is not related to these being incomplete types or anything (in the linked code, both A and B are complete types), and thus this is defined behaviour for dynamic_cast. However after that a null pointer is accessed; a clever compile can know that dynamic_cast can fail at that point and the pb->func1(); can do anything including not causing a null pointer exception or anything at all, or even calling the pb1->func on something that is not B.


An example with an incomplete type would be:

#include <iostream>

using namespace std;

class A {
public:
    virtual void func() {
        cout << "func():: in class A" << endl;
    }
    void func1(){
        cout<< "func1():: in class A";
    }
};

class B;

int main() {
    A a;
    A* pa = &a;
    B* pb = dynamic_cast<B*>(pa);
    return 0;
}

Now if you compile this with G++, you get

y.cc: In function ‘int main()’:
y.cc:20:32: error: cannot dynamic_cast ‘pa’ (of type ‘class A*’) to 
     type ‘class B*’ (target is not pointer or reference to complete type)
     B* pb = dynamic_cast<B*>(pa);

that is all sane C++ compilers will reject such code.

  • Thanks Anitti for figuring out , I meant to say pb points to an incomplete type as in gdb when i had tried (gdb) p *pB $3 = Correct me if I am wrong and thanks for replying on my doubt, i got the point :) – add2c Mar 09 '15 at 10:12