3

以下代码无法在 g++ 4.6.1 上编译:

template<class Base>
struct GetBase {
  Base * getBase() {
    return static_cast<Base *>(this);
  }
};

template<class Derived>
struct Parent : private GetBase<Derived> {
  using GetBase<Derived>::getBase;
  int y() {
    return getBase()->x();
  }
};

struct Child : public Parent<Child> {
  int x() {
    return 5;
  }
  int z() {
    return y();
  }
};

有错误

In member function ‘Base* GetBase<Base>::getBase() [with Base = Child]’:
    instantiated from ‘int Parent<Derived>::y() [with Derived = Child]’
    instantiated from here
error: ‘GetBase<Child>’ is an inaccessible base of ‘Child’

将 static_cast 更改为 reinterpret_cast 将使代码编译,并且在这种情况下可以工作,但我想知道这是否在所有情况下都是可接受的解决方案?即,是否存在指向基类的指针与此不同的情况?我假设如果父母有数据成员,这可能会发生多重继承?如果 GetBase 是第一个超类,是否保证 this 指针相等?

4

2 回答 2

3

我想知道这是否在所有情况下都是可接受的解决方案?

没有。 (见下文)

指向基类的指针是否与此不同?

是的。

  • 使用多重继承,不能期望基类具有相同的地址。

  • 根据编译器的不同,具有 vtable 指针的派生类可能与this没有 vtable 指针的基类不同。

当显式向上转换为基时,static_cast是适当的 C++ 转换。

于 2012-01-23T21:21:07.327 回答
1

一个好问题;它使我学到了一些新的东西static_cast

我认为以下代码实现了您想要的:为 CRTP 提供一个基类,该基类具有一个强制转换this为 Derived 类型的成员函数,但只能使该基类的直接后代可以访问它。它使用 GCC 4.3.4(在 ideone 测试)和 Clang(在 llvm.org 测试)编译。抱歉,我无法抗拒更改令我感到困惑的名称。

#include <iostream>

template<class Derived>
class CRTP {
protected:
  Derived * derived_this() {
    return static_cast<Derived *>(this);
  }
};

template<class Derived>
struct Parent : public CRTP<Derived> {
private:
  using CRTP<Derived>::derived_this;
public:
  int y() {
    return derived_this()->x();
  }
};

struct Child : public Parent<Child> {
  int x() {
    return 5;
  }
  int z() {
    return y();
  }
};

int main() {
  std::cout << Child().z() << std::endl;
  return 0;
}

此变体之所以有效,是因为继承是公共的,它支持将派生类指针标准转换为基类指针static_cast,以及 CRTP 所需的反向转换(从基类到派生类) . 您的代码中的私有继承禁止这样做。因此,我将继承公开,更改了要保护的方法,并Parent通过将using声明放入私有部分来进一步限制访问。

于 2012-01-23T22:54:07.760 回答