dynamic_cast的行为上升了另一个链

时间:2014-03-18 19:36:58

标签: c++

我刚刚在这里阅读这个问题 https://stackoverflow.com/a/332086/2689696 它告诉动态演员

  

你可以使用它而不仅仅是向下投射 - 你可以侧身或甚至向上投射另一个链。 dynamic_cast将寻找所需的对象并在可能的情况下返回它。

那么这究竟意味着什么,以及发生这种情况的限制/条件是什么。

我认为这就是声明的含义。演员阵容发生了,我也得到了一个明显的分段错误。

#include <iostream>
class base
{
public:
    virtual void print () = 0;
};

class childa : public base
{
public:
    char c1;
    virtual void print ()
    {
        std::cout << "childa\n";
    }
    void printout()
    {
        std::cout << "childa out\n";
    }
};

class childb : public base
{
public:
    int c2;
    virtual void print ()
    {
        std::cout << "childb\n";
    }
    void printin()
    {
        std::cout << "childb in\n";
    }
    void printout()
    {
        std::cout << "childb out\n";
    }
};

int main()
{
    base* b = new childa;
    b ->print();
    dynamic_cast<childa*>(b)->printout();
    dynamic_cast<childb*>(b)->printout();   // cast happens here and the output is printed
    dynamic_cast<childa*>(b)->c1 = 'a';
    dynamic_cast<childb*>(b)->c2 = 2;   // segfault here
}

这是我得到的输出并发生了​​段错误

  

childa
  孩子出去了   孩子出去

     

进程返回-1073741819(0xC0000005)执行时间:5.844 s
  按任意键继续。

编辑: 是的,我不检查空值是多么愚蠢。 但我想更多地了解其他问题(上/下/侧身)的评论

3 个答案:

答案 0 :(得分:5)

你在这里遇到未定义的行为:

dynamic_cast<childb*>(b)->printout();

强制转换实际上失败了(返回空指针)。您永远不会检查返回值并通过它调用成员函数。这是未定义的行为,任何事情都可能发生。在你的情况下,似乎因为函数不以任何方式访问this,即使通过空指针调用它也会执行得很好。但这并不能保证。


至于横向演员(或构建另一个链)是什么,需要更复杂的继承层次来证明:

struct base1
{
  virtual ~base1() {}
};

struct base2
{
  virtual ~base2() {}
};

struct child1 : base1
{};

struct child2 : base2
{};

struct both : child1, child2
{};


int main()
{
  child1 *c1 = new both();
  static_cast<base1*>(c1);  // ok
  static_cast<both*>(c1);  // ok
  static_cast<child2*>(c1);  // compile-time error, unrelated types
  dynamic_cast<child2*>(c1);  // succeeds, because the object is actually of type `both`, i.e. derived from `child2`; cast sideways
  static_cast<base2*>(c1);  // compile-time error, unrelated types
  dynamic_cast<base2*>(c1); // succeeds, because the object is actually of type `both`, i.e. derived from `base2`; cast up another chain

  base1 *b1 = new child1();
  static_cast<child1*>(b1);  // ok
  static_cast<both*>(b1);  // compiles, but produces UB, as the object is not of correct type
  static_cast<base2*>(b1);  // compile-time error, unrelated types
  dynamic_cast<base2*>(b1);  // fails (returns null pointer), because the object is not actually derived from `base2`.
}

答案 1 :(得分:0)

当且仅当dynamic_cast<T*>(a)T*的实例时,

*a才会返回非空T;否则,它返回NULL

从空指针调用方法或属性会产生未定义的行为。

答案 2 :(得分:0)

dynamic_cast的用处在他的回答中。使用此代码

int main()
{
    base* b = new childa;
    b ->print();

    childa* testA = dynamic_cast<childa*>(b);
    if (testA)
    {
        //Here you can be sure that your object is right
        testA->printout();
        testA->c1 = 'a';
    }
    else
        std::cout << "Error casting b to testA" << std::endl;

    childb* testB = dynamic_cast<childb*>(b);
    if (testB)
    {
        //Here you can be sure that your object is right
        testB->printout();
        testB->c2 = 2;
    }
    else
        std::cout << "Error casting b to testB" << std::endl;
}

您获得以下输出

childa
childa out
Error casting b to testB