C++ 动态浇铸失败

C++ 动态浇铸失败,c++,dynamic-cast,C++,Dynamic Cast,假设代码如下所示: #include <iostream> using namespace std; class dog { public: virtual ~dog() { } }; class yellowdog : public dog { int age; public: void bark() { cout << "woof." << endl;} }; int main() { dog *pd =

假设代码如下所示:

#include <iostream>

using namespace std;

class dog
{
 public:
   virtual ~dog()
   {

   }
};

class yellowdog : public dog
{
  int age;
  public:
    void bark() { cout << "woof." << endl;}
};

int main()
{
  dog *pd = new dog();
  yellowdog *py = dynamic_cast<yellowdog*>(pd);
  py->bark();
  cout << "py = " << py << endl;
  cout << "pd = " << pd << endl;
}
我理解为什么py=0。我知道有一个运行时检查,在该运行时检查中,无法将dog转换为yellowdog,因此py的值为0

我的问题是为什么py->bark仍然可以工作。为什么它仍然能够打印出纬纱


我对之前的代码表示歉意。现在请务必检查..

铸造失败的两个原因:

将指针强制转换为非指针类型,然后将其分配给指针。这会给您带来编译器错误

pd是指向dog的指针,而不是yellowdog,因此不可能进行向下转换,py将是空指针,取消引用将导致错误

从第二点开始,它就是给你带来麻烦的未定义的行为。根据定义,未定义的行为是未定义的,任何事情都可能发生。从崩溃到看似正常工作的事物,再到的外观。

py是空指针,因此py->bark调用未定义的行为。任何事情都有可能发生,包括看似有效的事情。与java或C++不同,C++如果没有访问空指针,就不能保证立即失败。以效率的名义,C++编译器通常会使用空指针检查。
碰巧的是,巴克根本不用这个,所以它可以正常工作也就不足为奇了。你不应该依赖于它,虽然不能保证它会工作,但这并不奇怪。

它实际上不工作:从空指针调用方法是未定义的行为。编译器可以决定是否使程序崩溃,如果该方法不使用数据成员(在您的情况下会发生这种情况),则让程序继续工作,清除磁盘中的所有数据,甚至在您所在的位置呼叫SWAT团队。你很幸运,在你的情况下没有发生什么坏事。

你在未定义的行为中做了什么,但你想知道为什么它在你的情况下仍然有效

原因是函数yellowdog::bark没有以任何方式使用this,加上它被内联到头中这一事实意味着编译器很可能只是为您内联了它的实现


换句话说,它看到你在一个yellowdog指针上调用了bark,并且知道如何实现它,它用cout@lakesh替换了这个调用。同样的东西也适用,我一开始没有意识到代码是错误的。@lakesh解决了第一个问题,现在这只是第二个问题。如何避免这种未定义的行为?@lakesh如何避免这种未定义的行为?不要取消对nullptr:P的引用。。。
woof.
py = 0x0
pd = 0x7fd4d34000e0