【问题标题】:Can be upcast and downcast both done using dynamic_cast in C++可以使用 C++ 中的 dynamic_cast 进行向上转换和向下转换
【发布时间】:2015-04-13 00:52:52
【问题描述】:

我在 c++ 中经历了dynamic_cast 的概念。

假设我们有一个class Base 和两个派生类class D1class D2,它们派生自Base。类Base有一个虚函数fun()

我的问题是:

  1. 向上和向下都可以用dynamic_cast完成吗?
  2. 如果是,哪一个更受欢迎和有利?在哪些情况下,我们可以在这方面选择失望/向上?
  3. 是否有任何演员不推荐或有害?

请结合使用案例进行解释,考虑到上述情况,以便更清楚地了解这一点。任何明确的解释都会非常有帮助。

【问题讨论】:

    标签: c++ visual-c++ inheritance virtual dynamic-cast


    【解决方案1】:
    1. 向上和向下都可以在dynamic_cast中完成吗?

    使用dynamic_cast 向上转换毫无意义。 Upcasts 总会成功的。 dynamic_cast 用于不确定向下转换是否会成功,因此您可以检查转换结果是否成功。

    假设你有一个函数f,它接受B&,并且必须决定它得到什么样的对象:

    void f(B& b) {
        D1* d1 = dynamic_cast<D1*>(&b); // notice the address-of operator!
        if (d1 != nullptr)
            std::cout << "We got a D1!\n";
        else if (dynamic_cast<D2*>(&b) != nullptr) // No need to assign to a variable.
            std::cout << "We got a D2!\n";
    
        // Or, with a reference:
        try {
            D1& d1_ref = dynamic_cast<D1&>(b); // reference!
            std::cout << "We got a D1!\n";
        catch (std::bad_cast const&) {
            std::cout << "It was NOT a D1 after all\n";
        }
    }
    

    重要的是,以上所有代码都对指针或引用进行操作。这就是我们在 C++ 中处理多态对象需要做的事情。我们不能在这里只使用值。

    1. 如果是。,哪一个更优选和有利。?在哪些情况下,我们可以在这方面选择失望/向上?

    在你的情况下,我们会:

    D1 derived;
    B& b = derived; // implicit upcast
    b.fun();
    
    static_cast<B&>(derived).fun(); // explicit upcast
    
    // But actually, no upcast is of course needed to call `fun`:
    derived.fun();
    

    Upcast 是隐式的,你不需要为此使用任何强制转换。如果您明确希望将对象视为基类类型,请使用 static_cast

    1. 是否有任何演员不推荐或有害?

    见上文。如需更多信息,请阅读cppreference entry on dynamic_cast

    【讨论】:

    • 谢谢。现在它很清楚了。但是考虑到这种情况,我们如何才能实现简单的向下转换?如果我们明确地想将一个对象视为基类类型,我们如何使用 static_cast 来做到这一点!
    • @ShivarajBhat:这非常有用,例如,在奇怪重复的模板模式 (CRTP - en.wikipedia.org/wiki/Curiously_recurring_template_pattern) 中,派生类继承自派生类传递到的类模板一个模板参数,基类通过static_cast-ing其this到使用模板参数派生类类型的派生类调用派生类的非虚方法。这是 ATL 和 WTL 所依赖的支柱之一。
    • @JohannGerell:谢谢 Johann。这些信息真的很有帮助。
    • 如果您的类层次结构在未来发生变化,则使用除隐式或动态转换之外的任何转换进行向上转换可能是有害的。假设类B 继承自A,并且您执行从BA 的静态转换。将来,您可以翻转层次结构,以便 A 继承自 B。静态转换仍然会成功并可能导致未定义的行为,因为它现在是向下转换,而隐式转换或动态转换是安全的。
    • @markasoftware 类层次结构更改是 API 和 ABI 重大更改无论如何。不管static_casts 是否存在,这都不是一个安全的改变:这不是唯一一种这种改变会导致无声的行为改变的场景……
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-16
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 2012-10-08
    相关资源
    最近更新 更多