【问题标题】:Casting pointer to derived class to reference to pointer to base class将指向派生类的指针转换为对指向基类的指针的引用
【发布时间】:2015-01-16 15:29:36
【问题描述】:

为什么我不能将派生类的指针转换为指向基类的指针?

struct Base { };
struct Derived : Base { };

int main()
{
    Derived* derived = nullptr;
    static_cast<Base*&>(derived);
}    

我明白了:

invalid static_cast from type 'Derived*' to type 'Base*&'

【问题讨论】:

  • 首先,static_cast 无效,因为您没有将返回值存储在任何地方。其次,如果你想将Derived* 变量转换为Base* 变量,那么去掉&amp;
  • 所以它应该类似于Base* base = static_cast&lt;Base*&gt;(derived);。但是,根据您当前的代码,您似乎可以简单地执行Base* base = nullptr;,因为转换Derived* 变量不会改变它的值。
  • 这是一个学术问题,还是你真的需要这个演员阵容?
  • 不,这不是一个学术问题。我需要调用一个函数作为参数Base*&amp;

标签: c++ pointers casting reference


【解决方案1】:

根据您的评论:

“不,这不是学术问题。我需要调用一个以Base*&amp;为参数的函数”

解决这个问题的正确方法是创建一个适当类型的新指针变量,并将它(或者更确切地说,对它的引用)传递给相关函数:

struct Base { };
struct Derived : Base { };

int main()
{
    Derived* derived = nullptr;
    Base* base = static_cast<Base*>(derived);
    my_function(base); // takes a Base*& argument

    // If you need the pointer value and are sure that
    // it's a Derived* type:
    derived = static_cast<Derived*>(base);
}

请注意,如果您在问题本身中包含相关信息(来自我上面引用的评论),您可能会更快收到此答案。

【讨论】:

  • 但是在你的解决方案中basemy_function修改,而derived没有改变。
  • @RuggeroTurra 是的。采用Base *&amp; 参数的函数不能保证将所指对象设置为Derived * 值。如果您确定指针将是Derived *,您可以在函数完成后强制转换和分配它。我会更新答案。
【解决方案2】:

因为Derived* 对象不是Base* 对象,并且两者完全有可能具有不同的内存布局或值表示(例如,如果BaseDerived 的对齐要求不同)。由于一个不是另一个,static_cast 无法执行转换。

如果您知道自己在做什么并且知道双关语没问题,请使用双关语工具 - reinterpret_cast:

reinterpret_cast<Base*&>(derived);

并注意滥用的任何后果(与reinterpret_cast 一样)。请特别注意,根据 C++11 3.10/10,就标准而言,通过转换结果进行的任何访问都将是未定义行为(尽管您的编译器可能会提供更强的保证)。

请注意,在一般情况下,从Derived*Base* 的转换不必是空操作。例如,如果涉及多重继承,它可能涉及地址转移。

【讨论】:

  • 类型双关语是将一种类型视为另一种类型的过程。像您提到的那样的演员实际上并不涉及类型双关语本身,因为该对象没有被取消引用。 (换句话说,reinterpret_cast 允许使用双关语,但使用 reinterpret_cast 本身并不构成双关语)。
  • @davmac 好吧,我有点假设 OP 实际上是在对演员阵容的结果做一些事情,这很可能是一个双关语。当然,就目前而言,这只是一个无操作。
  • 在 OP 给出的示例中(按照您的建议将 static_cast 更改为 reinterpert_cast 之后),对转换结果执行任何操作都会破坏别名规则,从而导致未定义的行为。 Base *Derived * 是不兼容的访问类型(open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf 草案的 3.10 第 15 段)。
  • @davmac 这是一个相当古老的草案。 3.10/15 根本不存在于已发布的 C++11 中。 C++11的终稿是N3337,在那里能找到相关的参考吗?我所拥有的是 5.2.10/7,11,这使得结果未指定。正如我在回答中所说:“如果您知道自己在做什么并且知道双关语类型没问题……”例如,您的编译器文档可以告诉您。
  • @Agnew 在您链接的草稿中,它是 3.10 第 10 段(通常称为 严格别名 规则,我可以向您保证它以一种或另一种形式存在在任何最新版本的标准中)。
【解决方案3】:

仅针对您的错误 改变这个

static_cast<Base*&>(derived);
to 
static_cast<Base*>(derived);
                ^^

请看这里http://ideone.com/1QuMLK

【讨论】:

    【解决方案4】:

    如果你想要参考,你需要做

    Base* ptr = static_cast<Base*>(derived);
    Base &ref = *ptr;
    

    你不能将指针指向一个引用——它们是完全不同的东西

    【讨论】:

    • “您不能将指针投射到引用” - 不正确;您可以将“指向 T 的指针”转换为“对指向 T 的指针的引用”。结果是对原始指针的引用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    • 2016-02-19
    • 2013-09-23
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    相关资源
    最近更新 更多