问题重构奇怪的重复模板模式
以下代码无法在 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 指针是否保证相等?
The following code fails to compile on 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();
}
};
with the error
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’
Changing the static_cast to a reinterpret_cast will get the code to compile and it will work in this case, but I'm wondering if this is an acceptable solution in all cases? i.e., is it ever the case that a pointer to a base class is not the same as this? I'm assuming with multiple inheritance this may happen if the parents have data members? If GetBase is the first superclass, are the this pointers guaranteed to be equal?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我想知道这是否在所有情况下都是可接受的解决方案?
不。(见下文)
是否存在指向基类的指针是这样的情况与此不一样吗?
是的。
通过多重继承,基类不能期望具有相同的地址。
根据编译器的不同,具有 vtable 指针的派生类可能与没有 vtable 指针的基类具有不同的
this
。根据
当显式向上转换为基数时,
static_cast
是适当的 C++ 转换。I'm wondering if this is an acceptable solution in all cases?
No. (See below)
is it ever the case that a pointer to a base class is not the same as this?
Yes.
With multiple inheritance, the base classes can not be expected to have the same address.
Depending on the compiler, a derived class with a vtable pointer may not have the same
this
as a base class that has no vtable pointer.When explicitly upcasting to a base,
static_cast
is the appropriate C++ cast.一个好问题;它让我了解了有关
static_cast
的新知识。我认为下面的代码实现了您想要的:为 CRTP 提供一个基类,其中的成员函数将
this
转换为 Derived 类型,但仅使其可供该基类的直接后代访问。它使用 GCC 4.3.4(在 ideone 测试)和 Clang(在 llvm.org 测试)进行编译。抱歉,我无法抗拒更改我觉得令人困惑的名称。此变体之所以有效,是因为继承是公共的,这使得可以将派生类指针标准转换为基类指针,也可以使用 static_cast 进行逆向转换(从基类到派生类) ,CRTP 需要的。代码中的私有继承禁止这样做。因此,我将继承公开,更改了要保护的方法,并通过将
using
声明放入私有部分,在Parent
中进一步限制访问。A good question; it caused me to learn something new about
static_cast
.I think the following code achieves what you want : provides a base class for CRTP with a member function that casts
this
to the Derived type, yet only makes it accessible to the direct descendants of this base class. It compiles with GCC 4.3.4 (tested at ideone) and Clang (tested at llvm.org). Sorry, I couldn't resist to changing the names that I find confusing.This variant works because the inheritance is public, which enables the standard conversion of a pointer-to-derived-class to a pointer-to-base-class, and so also the inverse conversion (from base to derived) with
static_cast
, which CRTP needs. Private inheritance in your code prohibited this. So I made inheritance public, changed the method to be protected, and inParent
further restricted access by putting theusing
declaration into private section.