考虑一下这个类的层次结构:
struct Animal { virtual ~Animal(); };
struct Cat : virtual Animal {};
struct Dog final : virtual Animal {};我的理解是,将final放在class Dog上可以确保没有人能够创建继承自Dog的类,这意味着没有人能够同时创建一个类-A Dog和IS-A Cat。
考虑这两个dynamic_cast:
Dog *to_final(Cat *c) {
return dynamic_cast<Dog*>(c);
}
Cat *from_final(Dog *d) {
return dynamic_cast<Cat*>(d);
}GCC、ICC和MSVC忽略了final限定符,产生了对__dynamic_cast的调用;这是不幸的,但并不令人惊讶。
令我惊讶的是,Clang和Zapcc都是from_final的最优代码(“总是返回nullptr"),但是生成了对__dynamic_cast的to_final调用。
这真的是错过了优化机会(在编译器中,显然有人花了一些精力在强制转换中尊重final限定符),还是由于一些我还没有看到的微妙的原因而不可能进行优化?
发布于 2017-06-12 02:38:50
好吧,我翻了一下Clang的查找此方法的源代码
/// isAlwaysNull - Return whether the result of the dynamic_cast is proven
/// to always be null. For example:
///
/// struct A { };
/// struct B final : A { };
/// struct C { };
///
/// C *f(B* b) { return dynamic_cast<C*>(b); }
bool CXXDynamicCastExpr::isAlwaysNull() const
{
QualType SrcType = getSubExpr()->getType();
QualType DestType = getType();
if (const PointerType *SrcPTy = SrcType->getAs<PointerType>()) {
SrcType = SrcPTy->getPointeeType();
DestType = DestType->castAs<PointerType>()->getPointeeType();
}
if (DestType->isVoidType()) // always allow cast to void*
return false;
const CXXRecordDecl *SrcRD =
cast<CXXRecordDecl>(SrcType->castAs<RecordType>()->getDecl());
//********************************************************************
if (!SrcRD->hasAttr<FinalAttr>()) // here we check for Final Attribute
return false; // returns false for Cat
//********************************************************************
const CXXRecordDecl *DestRD =
cast<CXXRecordDecl>(DestType->castAs<RecordType>()->getDecl());
return !DestRD->isDerivedFrom(SrcRD); // search ancestor types
}我对解析代码感到有点厌倦,但在我看来,并不是因为最终属性,您的from_final总是空的,而是因为Cat不在Dog派生的记录链中。当然,如果它没有final属性,那么它就会提前退出(就像Cat是Src时那样),但是它不一定总是空的。
我猜这有几个原因。第一种情况是,dynamic_cast在记录链上和下面都进行了转换。当Source记录具有最终属性时,您可以简单地检查链,如果Dest是祖先(因为不能从Source派生类)。
但是,如果这门课不是最后一堂课呢?我怀疑可能还有更多。也许多重继承使得查找强制转换比向下转换更困难?如果没有在调试器中停止代码,我所能做的就是推测。
我确实知道:isAlwaysNull是一个早期退出的函数。这是一个合理的断言,它试图证明结果始终为空。你不能像他们说的那样证明一个否定的,但你可以证明一个积极的。
也许您可以查看Git历史记录中的文件,并发送电子邮件给编写该函数的人。(或者至少添加了final检查)。
https://stackoverflow.com/questions/44489597
复制相似问题