我正在学习动态类型转换并搜索许多网站,得出的结论是,动态类型转换可以从基础进行转换,也可以从基础进行转换。 但是,当我从Base进行转换时,它给出了分段错误。 这是代码:
我期望从“ A”开始,但是即使在转换后也可以从D中获得
class A
{
public:
virtual ~A(){}
virtual void print()
{
std::cout << "from A"<<std::endl;
}
};
class B: virtual public A
{
public:
void print()
{
std::cout << "from B"<<std::endl;
}
};
class C: virtual public A
{
public:
void print()
{
std::cout << "from C"<<std::endl;
}
};
class D: public B, public C
{
public:
void print()
{
std::cout << "from D"<<std::endl;
}
};
int main(){
A* b = new B;
A* c = new C;
A* d = new D;
A* a = new A;
B* down = dynamic_cast<B*>(a); // this gives me problem
down->print();
A* up= dynamic_cast<A*>(d); // upcasten dont print from A either
up->print();
答案 0 :(得分:2)
使用dynamic_cast
转换指针时,需要在访问前检查结果指针以查看强制转换是否有效。访问无效的指针会导致未定义的行为。
B* down = dynamic_cast<B*>(a);
if (down == 0) {
std::cerr << "a is not a B!\n";
} else {
down->print();
}
您不需要使用dynamic_cast
进行“向上投射”。您可以将派生对象分配给父对象。如果该关系不存在,则会出现编译时错误。
A* up= d;
up->print();
由于print
是虚拟方法,因此up->print()
解析为派生的实现。但是,如果您希望查看基础的实现,则可以显式调用它。
d->A::print();
答案 1 :(得分:1)
从Base到Derived以及从Derived到Base进行转换的能力并不是dynamic_cast
的独特之处。关键特征是dynamic_cast
在检查最派生的对象实际上匹配(或实际上包含)后,在运行时 执行此类转换。 )所需的目标类型。这意味着,如果转换失败,则错误也是运行时错误,因此您的程序应该在运行时处理这些错误。
那是什么错误? dynamic_cast
可能会报告错误,如果在指针类型之间进行转换(例如,将X*
转换为Y*
,则返回空指针;如果正在转换,则抛出std::bad_cast
异常)在引用类型之间进行比较,例如X&
至Y&
。
从具有静态类型a
的{{1}}到A*
的铸造可能会产生指向B*
的有效指针或为null。后者正是您的示例所发生的情况:B
实际上指向类型为a
的完整对象,并且其中没有类型为A
的子对象。因此,强制类型转换返回空指针,然后将其立即用于调用成员函数B
。取消引用空指针值的任何尝试都是UB(未定义的行为),它很可能表现为段错误。
从这样的段错误中保护程序很容易:只需检查返回的值是否不为空:
down->print()
对于“从D”打印,是因为B* down = dynamic_cast<B*>(a);
if (down)
{
// Use down all you want
}
else
{
// Report an error, skip some actions
// or return from the function.
// But don't use `down`!
}
方法被声明为虚拟方法。这意味着即使您通过指向基础子对象的指针来调用最派生类的实现,也可以调用它。