【问题标题】:C++ - upcasting and downcastingC++ - 向上转型和向下转型
【发布时间】:2016-05-08 05:23:31
【问题描述】:

在我的例子中:

在向上转换时,第二个 d.print() 不应该调用 print "base" 吗?

不是将“d”派生对象向上转换为基类对象吗?

而在向下转型时,它有什么优势?

你能用实际的方式解释 upcast 和 downcast 吗?

#include <iostream>
using namespace std;

class Base {
public:
    void print() { cout << "base" << endl; }
};

class Derived :public Base{
public:
    void print() { cout << "derived" << endl; }

};

void main()
{
    // Upcasting
    Base *pBase;
    Derived d;
    d.print();
    pBase = &d;
    d.print();

    // Downcasting
    Derived *pDerived;
    Base *b;
    pDerived = (Derived*)b;
}

【问题讨论】:

  • 为什么你认为pBase 行应该改变d.print(); 的行为?你的意思是问pBase-&gt;print(); 吗?

标签: c++ class inheritance downcast upcasting


【解决方案1】:

向上转换在 C++ 中是隐式的,并且在处理虚拟调度时被大量使用。换句话说,您有一个指向Base 的指针,您可以从中访问整个类层次结构的公共接口,并且可以在运行时完成选择。这假设您的接口函数标记为virtual。示例:

Base* pBase; 
cin >> x; 
if(x == 0) // this is done at runtime, as we don't know x at compile time
    pBase = new Derived1;
else
    pBase = new Derived2;

pBase->draw(); // draw is a virtual member function

在调度在运行时完成的这些情况下非常有用。简单地说,向上转型允许将派生类视为基类(通过其公共接口)。

向下转换的用处不大,应尽可能避免使用 IMO。通常是糟糕设计的标志,因为很少需要将Base 对象转换为派生对象。可以通过dynamic_cast 完成(并检查结果),例如

Base* pBase = new Derived; // OK, the dynamic type of pBase is Derived
Derived* pDerived = dynamic_cast<Derived*>(pBase);
if(pDerived) // always test  
{
    // success
}
else
{
    // fail to down-cast
}

This link 提供了一个非常有用的主题介绍。

【讨论】:

  • 所以代码行:“pBase = new Derived1;”和“pBase = new Derived2;”代表实际上上扬?如果是这样,我们假设 x 为 0 并且 pBase 将指向“Derived1”类的对象。如果 pBase 指针是 "Derived1 *pBase" 会有什么区别?
  • @Mihai 当您事先不知道派生类型时,它很有用。在这种情况下,您可以使用指向 base 的指针来控制派生的层次结构。
  • 向下转型是糟糕的设计?这是一个疯狂的观点!向上转换是糟糕的设计,因为它会导致在编译时未知且在运行时不可预测的未定义行为。它实际上是一个向下转换的例子,提供了坚实的工作基础。
  • @Poriferous 我希望你意识到Base* p = new Derived 是(隐式)向上转换,而不是向下转换。向上转换的使用方式比向下转换更多。同样,IMO,dynamic_cast 应该少用。
  • @Poriferous 我同意不应该在动态类型上使用static_cast。向上转型是隐式的,它只是通过基指针控制类层次结构的接口。这对 IMO 很重要。
【解决方案2】:

您需要使用虚拟方法来启用RTTI

在您的情况下,由于您使用的是 C++,因此您应该依赖更安全的转换机制。因此,您应该使用dynamic_cast&lt;Derived*&gt;(b) 而不是(Derived*)b。这使您可以确保您实际上拥有一个指向基类(接口)的对象的指针,该基类是通过转换类型为Derived 的对象而获得的。 This page 提供了进一步的解释。

【讨论】:

  • 我不是downvoter(也许我应该......)但你的回答很好,但不是上面这个问题 - 我想这就是原因。
  • 好吧,为我辩护,这个问题也不是那么好。请让我知道您认为我应该如何改进我的答案。
猜你喜欢
  • 1970-01-01
  • 2013-02-17
  • 1970-01-01
  • 2011-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多