在我的例子中:
在上投时,第二个d.print()
不应该称印刷为"基地"吗?
不是将"d"派生对象向上转换为基类对象吗?
在放下时,它有什么优势?
你能用实际的方式解释一下向上和向下吗?
#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;
}
向上投射隐含在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
}
此链接提供了对该主题非常有用的介绍。
您需要使用虚拟方法才能启用 RTTI。
在您的情况下,由于您使用的是C++,因此您应该依靠更安全的铸造机制。因此,您应该使用 dynamic_cast<Derived*>(b)
而不是 (Derived*)b
。这使您可以确保您实际上拥有指向基类(接口)的对象的指针,该指针是通过强制转换类型为 Derived
的对象获得的。本页提供了进一步的说明。
如果你想称打印为"Base",你应该这样做;在这里,我们将派生类对象向上转换为此基类对象,所以,当我们调用 pBase->print()
时,它会转到基类并调用它;但是,如果print
函数是虚拟的,它将调用派生类,因为它在派生类中重写了此函数。
void main(){
// Upcasting
Base *pBase;
Derived d;
d.print();
pBase = &d;
pBase->print();
}