了解static_cast

时间:2014-04-16 20:46:41

标签: c++ 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;
}

ouptut是:

constr A
c: B1

3 个答案:

答案 0 :(得分:6)

这是因为未定义的行为可能会产生意外结果,包括似乎可以正常工作。

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

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


如果你问为什么编译器不会阻止它,那是因为你使用static_cast覆盖了类型检查。在所有演员阵容中,只有dynamic_cast会关注对象的真实类型,即使这很容易打破。

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

  • 编译器无法阻止您将A*转换为B*,即使它知道没有B个对象,因为B*非常有用为了再次投掷的单独目的。
  • 并且它无法阻止您使用B*来访问B成员。

问题在于你使用这个“假”B*来表示其他东西,而不是回归到它的真实类型。

答案 1 :(得分:1)

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标准

  

1.3.24 [defns.unde fi ned]本国际标准没有要求的未定行为行为[注:未定义   当本国际标准遗漏任何行为时,可能会出现这种行为   明确的行为定义或程序使用错误的行为   构造或错误的数据。允许的未定义行为范围从   完全忽视这种情况,结果不可预测   在记录中的翻译或程序执行期间表现   环境的方式特征(有或没有发行   (诊断消息),终止翻译或执行   (发布诊断信息)。许多错误的计划   构造不会产生未定义的行为;他们必须是   诊断。 - 结束说明]

答案 2 :(得分:0)

随时避免演员表演 - 这通常意味着出现了问题。

在您的示例中,您正在尝试将对象转换为具有其处理的更多权力。

就像对某人说这辆车是卡车并指向汽车。

当一个Trebant到达而不是一辆马车时,它会流下眼泪