将空基 class 指针转换为子 class 指针?

Cast empty base class pointer to child class pointer?

我有一些代码使用了从基本 class 类型到子 class 类型的有点偷偷摸摸的转换,其中子 class 类型被指定为模板范围。我假设因为 base class 没有声明数据成员并且大小为零,所以 base class 指针地址将与子指针地址相同,并且转换将成功。到目前为止代码 运行s 正确。

这是我正在做的事情的简化版本:

template <class RangeT>
struct CppIterator {
    CppIterator(const RangeT& range) { ... }
    // ... methods calling RangeT's members
};

// Base class, provides begin() / end() methods. 
template<class RangeT>
struct CppIterableBase {
    CppIterator<RangeT> begin() { 
        return CppIterator<RangeT>( *(RangeT*)this );  // Is this safe?
    }
    CppIterator<RangeT> end() { ... }
};

struct MyRange : CppIterableBase<MyRange> {
    // ... 
};

我的问题基本上是 - 代码是否符合犹太洁食标准?如果基为空,基指针是否总是等于子指针?它依赖于实现吗?以后我 运行 会惹上麻烦吗?

它很好地解决了我的问题,但我有点怀疑。

基数 class 不需要为空。

只要基是可访问的、明确的、非虚拟的,并且指向基的指针实际指向派生对象的基子对象,就可以有效地执行 static_cast 从指向派生指针的指向基的指针。编译器将对指针值执行任何必要的调整。

您所做的实际上是一种常见的模式,称为奇怪的重复模板模式(或 CRTP)。

reinterpret_cast 是一个完全不同的野兽,但是,在这种情况下,它可能是一张通往未定义行为领域的单程票(我懒得深入研究标准并弄清楚在哪个下极端情况不是 UB)。由于 C 风格的转换可以变成 reinterpret_cast(在这里,如果您不小心从 Base<Baz> 派生了 FooBaz 不是从 Base<Baz> 派生的) , 它不应该被使用。

此外,还有 可确保您不会意外地从 Base<Bar> 派生出 Foo - 仅使用 static_cast 不会阻止 if Bar 也派生自 Base<Bar>.

这是 CRTP。

使用 static_cast<Derived*>(this) 更安全,因为 C 风格的转换在某些情况下会是 "too strong".

使用 Foo<> 作为 CRTP 基础 class:

只要有问题的 Foo<Derived> 实际上是 Derived 的基础,那么 static_cast<Derived*>(this) 在运行时是安全的并且做正确的事情。

static_assert of is_base_of 可以减少此处可能的错误来源之一,但不是全部。如果 struct Bar : Foo<Derived> 上面的转换有未定义的行为,我知道没有办法检查那个错误。