Rak*_*kib 15 c++ dynamic-cast comma typeid
我正在研究一种通用的非侵入式智能指针实现.我在第4节中有些困惑.一个声明是
仅当结果类型是多态类类型的左值时,才计算作为typeid运算符的参数提供的表达式.
相关的示例代码是:
template<typename T>
void* startOfObject(T* p) {
void* q=static_cast<void*>(p);
typeid(q=dynamic_cast<void*>(p),*p); // This line
return q;
}
Run Code Online (Sandbox Code Playgroud)
AFAIU,它意味着q=dynamic_cast<void*>(p)如果结果类型是多态类类型的左值,则将对其进行评估.该结果意味着评价的结果dynamic_cast<void*>(p)(我想),所以dynamic_cast在任何情况下被应用.文章陈述(据我所知),如果p不是多态的话dynamic_cast就不会应用,但为什么呢?在应用它之前,如何知道结果是否是多态的?如果有人详细描述了如何执行完整的语句,将会很有帮助.
另一种说法是
如果p为NULL也存在问题 - typeid将抛出std :: bad cast.
我看到的问题是取消引用,如果p是NULL,而不是typeid(虽然它可能抛出bad_typeid,但这不是因为转换).dynamic_cast会返回一个NULL类型的指针void*,如果p是NULL,而且typeid应该能够推断出类型的信息.这是一个错字,还是我错过了什么?
MSa*_*ers 11
基本上编写以下代码是一个奇特的技巧
if (T is polymorphic)
return dynamic_cast<void*>(p);
else
return static_cast<void*>(p);
Run Code Online (Sandbox Code Playgroud)
使用的技巧是以typeid(expr)两种方式之一进行评估.如果编译器确定expr具有非多态类型,则继续使用其静态类型.但是如果expr有动态类型,它会expr在运行时进行评估.因此,当且仅当*p逗号是多态的时,才会对逗号运算符之前的赋值进行求值.
由于这个原因,null情况很复杂.如果T不是多态的,那么typeid(*p)在编译时由编译器替换,并且运行时空指针根本不重要.如果T是多态的,则应用空指针解引用的特殊处理,并且该特殊处理表明std::bad_typeid抛出了异常.
逗号运算符具有从左到右的关联性,并从左到右进行求值.这意味着表达式的结果q=dynamic_cast<void*>(p),*p是*p.因此,仅当类型*p为多态时才评估动态强制转换.
关于NULL问题标准规定:
当typeid应用于类型为多态类类型(10.3)的左值表达式时,结果引用一个type_info对象,表示左值引用的最派生对象(1.8)的类型(即动态类型) .如果通过施加一元运算符*的指针所得到的左值表达式和指针是空指针值(4.10)时,typeid的表达抛出bad_typeid异常(18.5.3).
由于C++是一种静态类型语言,因此即使在涉及多态行为的情况下,每个表达式的类型在编译时也是已知的.
在编译时已知某个类是否是多态的,在程序执行之间将不会更改此属性.
如果编译器看到的EXPR中typeid(expr)不会产生多态类类型的值,它只会把EXPR "未计算",这相当于在运行时不执行它.
!!!
重要的是要注意expr必须仍然有效,我们不能typeid用来潜在地忽略一个不正确的表达式; 如果表达式格式错误,仍必须发出编译器诊断.
仅仅因为expr将被"未评估"并不意味着我们可以让它包含一个格式错误的子表达式.
struct A { }; // not polymorphic
...
A * ptr = ...;
typeid (dynamic_cast<void*> (ptr), *ptr); // ill-formed
Run Code Online (Sandbox Code Playgroud)
因为ptr不是指向多态类的指针,所以我们不能在dynamic_cast<T>其中使用它T = void*,如中所述[expr.dynamic.cast]p6.
这将使typeidthrow成为异常,因此它不会产生未定义的行为,但如果使用此类实现,则应准备好处理异常.
5.2.8p2类型识别[expr.typeid](...)如果通过将一元运算
*符应用于指针并且指针是空指针值(4.10)来获得glvalue表达式,则typeid表达式将抛出与类型处理程序匹配的类型的异常(15.1)std::bad_typeid例外(18.8.3)
这意味着如果结果类型是多态类类型的左值,则将评估q = dynamic_cast(p).结果意味着评估dynamic_cast(p)的结果(我猜).
不,作者所说的是,如果整个表达式的结果类型是多态类类型,那么将对表达式进行求值.
注意:"整个表达式"指的是...in typeid(...),在您的情况下; q=dynamic_cast<void*>(p),*p.
逗号运算符
逗号运算符将采用两个操作数expr1和expr2,它将通过计算expr1开始,然后丢弃该值,之后它将计算expr2并产生该表达式的值.
把它放在一起
这意味着使用逗号运算符的结果类型就好像它只包含右侧表达式,并且在下一行中,编译器将检查以便expr2的结果是一个多态类的类型.
typeid (expr1, expr2)
Run Code Online (Sandbox Code Playgroud)
typeid (q=dynamic_cast<void*>(p), *p)
// expr1 = q=dynamic_cast<void*>(p)
// expr2 = *p
Run Code Online (Sandbox Code Playgroud)
注意:在C++ 03中,结果类型必须是多态左值,在C++ 11中,这已被更改为多态类类型的glvalues.
| 归档时间: |
|
| 查看次数: |
681 次 |
| 最近记录: |