1

Here are 2 codes first:

#include<iostream>
using namespace std;

class A{
  public:
     virtual void  f()
    {
      cout<<"A"<<endl;
    }
};
class B: public A{
  public:
    virtual void  f()
    {
      cout<<"B"<<endl;
    }
};
int main()
{
  A* pa=new A();
  B* pb=new B();
  A* upCastpa= static_cast<A*>(pb);
  B* downCastpb=static_cast<B*>(pa);
  upCastpa->f();
  downCastpb->f();
  return 1;
}

one display

B
A

Therefore I think what really matters is the objected the pointer pointing to. However, if I remove virtual form A::f(), like this;

#include<iostream>
using namespace std;

class A{
  public:
     void  f()
    {
      cout<<"A"<<endl;
    }
};
class B: public A{
  public:
    virtual void  f()
    {
      cout<<"B"<<endl;
    }
};
int main()
{
  A* pa=new A();
  B* pb=new B();
  A* upCastpa= static_cast<A*>(pb);
  B* downCastpb=static_cast<B*>(pa);
  upCastpa->f();
  downCastpb->f();
  return 1;
}

The code will displayed A "stop" What happened? If the important thing is the objected the pointer pointing to.

it suppose to display A B instead of corrupted.

what happened?

I really appreciate any advice or instruction. Thanks a lot.

StevenR
  • 702
  • 1
  • 8
  • 17
  • All B's are A's but not all A's are B's. You'll have to use dynamic_cast to determine if your A's a B. – andre Oct 18 '12 at 14:03
  • @ahenderson: in the first case, but `dynamic_cast` won't (of course) work in the second case where `A` is not polymorphic. – CB Bailey Oct 18 '12 at 14:05
  • Hopefully you do realize that accessing an object A via a B* pointer can cause all kinds of problems? Like trying to accessing members which aren't actually there and stuff... So basically, both examples are flawed, and contain undefined behavior... oh and never use static_cast with pointer types... it's not what it was intended for, see http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast – codeling Oct 18 '12 at 14:06
  • If you make `f` nonvirtual in `B` too then the code will appear to work again. – Neil Oct 18 '12 at 14:10

3 Answers3

2

Irrespective of the presence or absence of virtual function:

A* pa=new A(); 
B* downCastpb=static_cast<B*>(pa); 

causes an Undefined Behavior.

When you use static_cast to cast an object to a type that it is not, it causes Undefined behavior. Once you have an code that produces undefined behavior it is useless to try and find reasoning for the output observed. The compiler is free to show any behavior, a crash, a weird result or an absoultely fine working code.You are completely at the mercy of the compiler.

Reference:

C++11 Standard 5.2.9 [expr.static.cast]

A prvalue of type "pointer to cv1 B", where B is a class type, can be converted to a prvalue of type "pointer to cv2 D", where D is a class derived from B, if a valid standard conversion from "pointer to D" to "pointer to B" exists, cv2 is the same cv-qualification as, or greater cv-qualification than, cv1, and B is neither a virtual base class of D nor a base class of a virtual base class of D. The null pointer value is converted to the null pointer value of the destination type. If the prvalue of type "pointer to cv1 B" points to a B that is actually a subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • Do you know if you get _undefined behavior_ merely by generating a value that is _undefined_ (why not _unspecified_?) or only by using such a value? (I thought it was the latter but now I'm not so sure.) – CB Bailey Oct 18 '12 at 14:20
  • @CharlesBailey: This is similar to a [Q i asked before](http://stackoverflow.com/q/8804612/452307).There is thin line when actually an Undefined behavior occurs and it is often debatable.So to be honest, I cannot say for sure. – Alok Save Oct 18 '12 at 15:14
0

This is polymorphism. You should write virtual void f() into your base class A and write void f() into inheritor class B

Ruu
  • 1,245
  • 9
  • 9
0

By removing the first virtual, you effectively prevent it from going into the vtable. This means class A's vtable is now empty. But, because class B does have a virtual function, it has an entry in its vtable.

So, when you downcast an A* into a B*, and then call f through it, the call will be looking for a function f in an empty vtable. Not finding it, it's going to complain about code corruption.

In practice, in the general case, your example 1 won't work either. The reason it does work in this particular case is that the vtable for A and B are exactly the same.

João Mendes
  • 1,719
  • 15
  • 32