我正在尝试使用pimpl成语。特别是,实现类将实现另一个接口:
// public_class.h
class PublicClass
{
public:
/* public interfaces here */
private:
class _PublicClass_impl;
friend class _PublicClass_impl;
protected:
_PublicClass_impl * const _impl;
};
// public_class.cpp
class PublicClass::_PublicClass_impl : public SomeInterface
{
friend class PublicClass;
/* all sort of stuff ... */
};
我的问题是,在下列情况下可以使用哪些演员阵容?
// some_other_class.h
class SomeOtherClass : private PublicClass
{
void some_function()
{
// definition of _PublicClass_impl is unknown
// thus, _impl is opaque
SomeInterface * interface = dynamic_cast<SomeInterface *>(_impl); //??
/* more code ... */
}
};
在这种情况下,dynamic_cast会正常工作吗?在这种情况下是否可以使用任何其他类型的演员?
答案 0 :(得分:1)
如果我没有弄错,根本不需要任何明确的演员,因为SomeInterface
是_PublicClass_impl
的基类,你总是可以隐式演员到基类。
我实际上尝试在GCC(4.5.1)中编译代码而没有dynamic_cast
,确实没有错误或警告(我将SomeInterface
定义为空类)。
但是,一个相关的问题引起了我的兴趣:为什么编译器会考虑SomeInterface
确实是_PublicClass_impl
的基类这一事实,尽管后者在所讨论的点上是不透明的? / p>
我最接近解释的是C ++标准第5条§11.2:
如果可以访问基类,则可以隐式地将指向派生类的指针转换为指向该基类的指针 class(4.10,4.11)。
如果由于某种原因你想要使用一个明确的演员,一个简单的静态演员应该没问题:
SomeInterface *interface = static_cast<SomeInterface *>(_impl);
答案 1 :(得分:1)
据我所知,没有一种可靠的方法来做你想做的事。 reinterpret_cast或c-style强制转换可能有效(行为未指定),但其他行为都是未定义的行为,当它允许你编译它时。
n4242的5.2.7.2(我知道它不是官方标准,但它应该是关闭的)关于dynamic_cast(v),如果T是指针类型,则v应该是指向完成类类型的指针的prvalue,结果是类型T的prvalue。如果T是左值引用类型,则v应该是完整类的左值类型,结果是由T引用的类型的左值。如果T是右值引用类型,则v应该是具有完整类类型的表达式,并且结果是由T.引用的类型的xvalue。 / p>
所以dynamic_cast不起作用。
static_cast不起作用,因为两种类型之间没有定义任何有效的转换。
5.2.10.7说关于reinterpret_cast(v),
指向对象的指针可以显式转换为指向不同对象类型的指针.69当“指向T1的指针”类型的prvalue v转换为“指向cv T2的指针”类型时,结果为static_cast( static_cast(v))如果T1和T2都是标准布局类型(3.9)并且T2的对齐要求不比T1更严格。将“指向T1的指针”类型的prvalue转换为“指向T2的指针”类型(其中T1和T2是对象类型,T2的对齐要求不比T1更严格)并返回其原始类型会产生原始类型指针值。任何其他此类指针转换的结果都未指定。
所以reinterpret_cast可能会起作用。
最后,不使用强制转换不起作用,因为编译器不知道类型之间的关系。