-Wreinterpret-base-class在Clang / C ++中的含义是什么?

时间:2015-12-22 13:08:38

标签: c++ clang

我有这个类层次结构:

class Base {
  // no virtual stuff
}

class Property : Base {
  // no virtual stuff
}

typedef const Property* PropertyID;

template<typename T>
class TypedProperty : public Property {

  // One virtual method
  virtual bool ValidateValue(T& value) const {  return true; }

  inline const T& GetDefaultValue() const { return m_default_value; }

}

然后它会像这样使用:

template<typename T>
const T& DoSomething(PropertyID property) {
  return reinterpret_cast<const TypedProperty<T>*>(property)->GetDefaultValue();
}

Clang吐出这个警告:

  

警告:'reinterpret_cast'从类'const TypedProperty *'到它的基础非零偏移'PropertyID'(又名'const Property *')的行为与'static_cast'不同[-Wreinterpret-base-class]

Xcode中的“Fix-it”说:

  

使用'static_cast'在向下转换时正确调整指针。

这是什么意思,特别是“从非零偏移的基础”部分?

使用reinterpret_cast vs static_cast会出现什么问题:它只是(正确的AFAIK)投射指针?我知道传递的对象是const TypedProperty<T>*

3 个答案:

答案 0 :(得分:2)

struct A{ int x; };
struct B:A{};
struct C:A,B{};

这里我们有3种类型。 C的一个实例中包含两个A个实例。

这两个实例的地址不同。

重新解释强制转换只会获取地址的指针值,并将其视为指向C的指针。并且C的实例只有一个地址,而不是两个,因此两个子对象A都不能具有该值。

上升也不会起作用(reinterpret_cast<B*>(pointer_to_c)),但是在上升时使用显式强制转换比在下降时使用reinterpret_cast更简单。

一般情况下,reinterpret_cast对于指针只是一个好主意,如果你在另一边做了相反的reinterpret_cast,或者你在char*使用它来获取原始字节

答案 1 :(得分:1)

除了涉及钻石的Yakks示例之外,您还可以通过简单的多重继承来获取它:

struct A { int x; };

struct B { int y; };

struct C : A, B {};

在这种情况下,C中的A和B对象不能具有相同的地址。其中一个将被抵消。基本上,一般来说,从一个孩子到另一个孩子重新解释演员阵容是不安全的,你应该静态演员。

答案 2 :(得分:1)

问题中的信息似乎否定了多重继承的答案。所以vtable答案更有可能。

如果TypedProperty至少有一个虚函数且Property没有虚函数,那么您将得到完全描述的问题。

TypedProperty对象中的第一件事是vtable指针,第二件事是Property基类。如果static_castProperty*TypedProperty*,编译器会通过减去vtable指针的大小来调整。如果你reinterpret_cast没有调整,那么结果指针就不正确了。

错误消息中的“非零偏移”告诉您指针中存在一些差异。唯一的问题是它是否是多重继承(问题似乎表明不是这种情况)或其他东西。

现在更新了原始问题,以显示原因是TypedProperty中至少有一个虚拟函数和Property中没有虚函数,也没有基类中的虚函数。请理解,reinterpret_cast static_cast执行reinterpret_cast工作的失败是一个特定于实现的细节,恰好在几乎所有实现中都匹配。 标准答案是这样的reinterpret_cast 总是错误的!。您永远不能TypedProperty将有效的基类指针转换为有效的派生类指针。

如果reinterpret_cast中没有虚函数,或者基类中至少有一个虚函数,static_cast将代替{{1}},但仍然会出错。这是一个意外工作的未定义行为的例子。不要依赖它。