【问题标题】:Understanding static_cast了解 static_cast
【发布时间】:2014-04-16 20:46:41
【问题描述】:

我在理解下面的代码时遇到了一些问题。为什么我可以调用 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

【问题讨论】:

    标签: c++ static-cast


    【解决方案1】:

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

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

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


    如果您要问为什么编译器不阻止它,那是因为您使用 static_cast 覆盖了类型检查。在所有的转换中,只有dynamic_cast 关注对象的真实类型,即使这样也很容易被破坏。

    您正在以一种非常不安全的方式编写两个定义良好的操作。

    • 编译器无法阻止您将A* 转换为B*,即使它知道没有B 对象,因为B* 对于再次转换的单独目的非常有用.
    • 它不能阻止您使用B* 访问B 成员。

    问题是你使用这个“假”B* 来做一些事情,而不是转换回它的真实类型。

    【讨论】:

    • 谢谢。我知道编译器不应该阻止它,但想知道为什么可以调用 c() 函数并获得正确的值。
    • @user1273055:好吧,任何可能都会发生,这是未定义的行为。实际可能发生的是B::c() 使用B::x 将被存储的位置,就在A 子对象之后。它会覆盖属于其他对象的内存。在您的情况下,该值以前为 0 并变为 1,但它可能是该位置的真正所有者设置的任何值。
    • 即使这不是未定义的行为,x 也永远不会初始化,因此任何值都是“正确”值。
    • @RetiredNinja:对象(不包括x)是值初始化的,它将所有成员归零(同样,不包括任何x)。我想这就是预先建立0 的期望。
    【解决方案2】:

    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.undefined] 未定义的行为 本国际标准对其没有要求的行为 [注:未定义 当本国际标准省略任何 行为的明确定义或当程序使用错误的 构造或错误的数据。允许的未定义行为范围从 完全无视情况,结果不可预知, 翻译或程序执行过程中的行为 环境的方式特征(有或没有发行 诊断消息),终止翻译或执行 (伴随诊断信息的发布)。许多错误的程序 结构不会产生未定义的行为;他们必须是 确诊。 ——尾注]

    【讨论】:

    • 这肯定与对话有关。
    • 你这个答案的第一句话是明确错误的。如果问题解决了,我会改进我的投票。
    【解决方案3】:

    随时避免强制转换 - 这通常意味着出现问题。

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

    这就像对某人说这辆车是一辆卡车,然后指着一辆车。

    当 Trebant 到达而不是马车时,它会以泪水告终

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-29
      • 2020-12-24
      • 2011-06-06
      • 1970-01-01
      相关资源
      最近更新 更多