以下代码无法在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是第一个超类,这个指针是否保证相等?
答案 0 :(得分:3)
我想知道在所有情况下这是否是可接受的解决方案?
否。(见下文)
是否一直指向基类的指针与此不一样?
是强>
使用多重继承时,不能指望基类具有相同的地址。
根据编译器的不同,带有vtable指针的派生类可能与没有vtable指针的基类具有相同的this
。
当明确向上转换为基类时,static_cast
是适当的C ++强制转换。
答案 1 :(得分:1)
一个好问题;它让我学到了关于static_cast
的新内容。
我认为以下代码可以达到您的目的:为CRTP提供一个基类,其成员函数将this
强制转换为Derived类型,但只允许该基类的直接后代访问它。它汇编了GCC 4.3.4(tested at 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;
}
这种变体是有效的,因为继承是公共的,它允许将指向派生类的指针标准转换为指向基类的指针,以及使用{转换(从base到派生)的逆转换。 {1}},CRTP需要。您的代码中的私有继承禁止此操作。所以我将继承公开,更改了要保护的方法,并在static_cast
中通过将Parent
声明放入私有部分来进一步限制访问。