繁体   English   中英

了解static_cast

[英]Understanding static_cast

我在理解下面的代码时遇到了一些问题。 为什么我可以调用c()函数?

#include <iostream>
#include <list>


using namespace std;

class A
{};

class B : public A
{
 public:
  void c() { cout << "c: B" << ++x << endl; }   
  int x;
};

int main(void) {
  class A *a = new A();
  static_cast<B*>(a)->c();

  return 0;
}

输出是:

constr A
c: B1

这是因为未定义的行为可能会产生意想不到的结果,包括看起来可行。

任何事情都可能发生,这是未定义的行为。 实际上可能发生的情况是B::c()使用了B::x会被存储在B实例中的位置,紧接着A子对象1 并且它将覆盖属于其他对象的内存。 在您的情况下,该值以前为0并变为1 ,但是它可能是该位置的真实所有者放置在其中的任何值。

(1)如果编译器实现空基类优化,则B::xB::A子对象实际上可能重叠。


如果您问为什么编译器不能阻止它,那是因为您已经使用static_cast覆盖了类型检查。 在所有类型转换中,只有dynamic_cast注意对象的真实类型,甚至很容易破坏。

您正在以非常不安全的方式编写两个定义明确的操作。

  • 即使编译器知道不存在B对象,编译器也无法阻止您将A*强制转换为B* ,因为B*对于单独再次强制转换非常有用。
  • 并且它不能阻止您使用B*访问B成员。

问题是,您将此“伪” B*用于其他类型,而不是转换回其真实类型。

dynamic_cast可以提供有关成功或失败的信息(如果您具有至少一个虚拟函数,而我假设您的真实程序会拥有),而static_cast则不能。 static_cast不使用运行时类型标识。 进行强制转换是有正当理由的,但是您需要遵守规则以避免未定义的行为。

向下转换时,首选动态投放而不是静态投放。 当然,我不知道为什么有人会用继承而不是一个虚拟函数来编写程序(除非这只是一个简单的演示问题的例子),但是这样做可能有用例或原因。 http://en.cppreference.com/w/cpp/language/dynamic_cast

如果绝对必须使用static_cast,则需要遵循有关何时使用的规则。 不幸的是,static_cast不会为您提供异常或失败通知,因此必须谨慎使用。 http://en.cppreference.com/w/cpp/language/static_cast

2)如果new_type是指向某个类D的指针或引用,而表达式的类型是指向其非虚拟基数B的指针或引用,则static_cast执行向下转换。 这种static_cast不会进行任何运行时检查以确保对象的运行时类型实际上是D,并且只有在通过其他方式(例如实现静态多态性)保证了此前提条件的情况下,才可以安全地使用该对象。 安全下调可以通过dynamic_cast完成。

为了解决您的示例为何起作用的问题,请允许我引用ANSI std。

1.3.24 [defns.undefined]未定义的行为,本国际标准没有规定任何要求的行为[注:当本国际标准省略任何明确的行为定义或程序使用错误的构造或错误的数据时,可能会出现未定义的行为。 允许的未定义行为的范围从完全忽略具有无法预测结果的情况到在以环境特征的书面方式在翻译或程序执行过程中表现为行为(带有或不带有诊断消息),终止翻译或执行(带有发布)诊断消息)。 许多错误的程序构造不会导致未定义的行为; 他们需要被诊断。 —尾注]

随时避免进行强制转换-这通常意味着出了点问题。

在您的示例中,您试图将一个对象转换为具有更多可处理的能力。

这就像对某人说这辆车是一辆货车,指向一辆车。

当Trabant到达而不是货车时,它会流下眼泪

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM