我正在学习动态铸造和搜索很多网站,我得出的结论是,动态铸造可以从基础到派生到基础。但是,当我从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();
发布于 2019-05-22 13:27:41
当使用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();
发布于 2019-05-22 13:13:58
从基础到派生和从派生到基础的转换能力不是dynamic_cast
的独特特征。关键特性是dynamic_cast
在运行时执行这种转换,检查大多数派生对象实际上匹配(或实际上包含)所需的目标类型。这意味着,如果转换失败,错误也是运行时错误,您的程序应该预先设置以在运行时处理此类错误。
这些错误可能是什么?dynamic_cast
可能报告错误,方法是:如果在指针类型之间转换(例如X*
到Y*
),则返回空指针;如果在引用类型之间转换(如X&
到Y&
),则抛出std::bad_cast
异常。
使用静态类型a
将A*
转换为B*
可以生成指向B
的有效指针或null。后者正是在您的示例中发生的:a
实际上指向一个类型为A
的完整对象,其中没有B
类型的子对象。因此,cast返回空指针,然后立即用于调用成员函数down->print()
。任何取消引用空指针值的尝试都是UB (未定义的行为),这很可能表现为分段错误。
保护您的程序不受这种分段错误的影响很容易:只需检查返回的值是否为空:
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`!
}
至于打印"from D",这是因为print
方法被声明为虚拟的。这意味着来自大多数派生类的实现将被调用,即使您通过指向基子对象的指针调用它。
https://stackoverflow.com/questions/56265039
复制