C++ 失败和格式错误的强制转换
您能否解释一下C++ 失败和格式错误的强制转换,c++,casting,C++,Casting,您能否解释一下格式错误的强制转换和失败的强制转换之间的区别。 例如: class A { virtual void f(); }; class B { virtual void g(); }; class D : public virtual A, private B { }; void g() { D d; B* bp = (B*)&d; // cast needed to break protection A* ap = &d;
格式错误的强制转换
和失败的强制转换
之间的区别。
例如:
class A { virtual void f(); };
class B { virtual void g(); };
class D : public virtual A, private B { };
void g() {
D d;
B* bp = (B*)&d; // cast needed to break protection
A* ap = &d; // public derivation, no cast needed
D& dr = dynamic_cast<D&>(*bp); // fails
ap = dynamic_cast<A*>(bp); // fails
bp = dynamic_cast<B*>(ap); // fails
ap = dynamic_cast<A*>(&d); // succeeds
bp = dynamic_cast<B*>(&d); // ill-formed (not a run-time check)
}
类{virtual void f();};
类B{virtualvoid g();};
D类:公共虚拟A,私有B{};
void g(){
D;
B*bp=(B*)&d;//需要强制转换才能断开保护
A*ap=&d;//公共派生,不需要强制转换
D&dr=dynamic_cast(*bp);//失败
ap=动态_cast(bp);//失败
bp=动态_cast(ap);//失败
ap=dynamic_cast(&d);//成功
bp=dynamic_cast(&d);//格式错误(不是运行时检查)
}
尽管名称不同,但当您使用
动态\u cast
执行向上转换(派生->基)时,转换在编译时完成,其行为方式与静态\u cast
或隐式转换相同-如果基不明确或无法访问,则程序格式错误,这意味着编译器必须生成诊断。§5.2.7[解释动态铸造]/p5:
[对于表达式动态_cast(v)
:]
如果T
为“指向cv1b
”且v
为“指向cv2d
”类型
因此,B
是D
的基类,结果是指向
v指向的D
对象的唯一B
子对象。同样,如果
T
是“对cv1b
的引用”,并且v
具有cv2d
类型,因此B
是D
的基类,结果是
D
由v
引用的对象。67结果是左值
如果T
是左值引用,或者如果T
是右值,则为x值
参考资料。在指针和引用情况下,程序都是
如果cv2
比cv1
或如果B
是D
的不可访问或不明确的基类
67指向或引用的最派生对象(1.8)
v可以包含其他B对象作为基类,但这些被忽略
在其他情况下(向下或侧向),检查在运行时执行。如果失败,则转换结果是指针转换的空指针,引用转换的异常为
std::bad_cast
。无论名称如何,当您使用dynamic_cast
执行向上转换(派生->基)时,强制转换在编译时完成,其行为方式与静态\u强制转换或隐式转换相同-如果基不明确或不可访问,则程序格式错误,这意味着编译器必须生成诊断。§5.2.7[解释动态铸造]/p5:
[对于表达式动态_cast(v)
:]
如果T
为“指向cv1b
”且v
为“指向cv2d
”类型
因此,B
是D
的基类,结果是指向
v指向的D
对象的唯一B
子对象。同样,如果
T
是“对cv1b
的引用”,并且v
具有cv2d
类型,因此B
是D
的基类,结果是
D
由v
引用的对象。67结果是左值
如果T
是左值引用,或者如果T
是右值,则为x值
参考资料。在指针和引用情况下,程序都是
如果cv2
比cv1
或如果B
是D
的不可访问或不明确的基类
67指向或引用的最派生对象(1.8)
v可以包含其他B对象作为基类,但这些被忽略
在其他情况下(向下或侧向),检查在运行时执行。如果失败,则转换结果为指针转换的空指针,以及引用转换的异常。让我们从头开始,看看每种情况:
class A { virtual void f() {} };
class B { virtual void g() {} };
class D : public virtual A, private B { };
void g() {
D d;
B* bp = (B*)&d;
[continue...]
C++强制转换(reinterpret_cast
的例外,它只强制转换原始指针值,而不进行任何调整或运算)不允许“忽略”继承访问级别(),C样式强制转换可以
使用上述代码,bp是指向有效对象的指针,但访问级别被完全绕过。这可能是个问题吗
答案是肯定的,以以下为例:
class A { virtual void f() {} };
class B { virtual void g() {}
public:
~B() {cout << "B's destructor";} // You can destroy B objects but NOT D objects from B* pointers
};
class D : public virtual A, private B {
~D() {cout << "D's destructor";}
};
void g() {
D *d = new D();
B* bp = (B*)d; // Bypass access permissions
delete bp; // This shouldn't happen! D's destructor will NOT be called! Undefined Behavior!
这是一个完全合法的向上投射。以下演员阵容不合法:
D& dr = dynamic_cast<D&>(*bp);
。。。如果bp指向(引用)最派生对象的公共基类子对象,则
派生最多的对象的类型有一个基类,类型为a,结果是明确的和公共的
点(引用)是指最派生对象的子对象
但同样:权限出错,演员阵容失败(没有格式错误,再次失败)
随后的强制转换已经无效,因为ap
为NULL
bp = dynamic_cast<B*>(ap);
其中,D
对象指针被强制转换为公共基类
最后一个演员阵容最终是结构不良的
bp = dynamic_cast<B*>(&d);
bp=dynamic\u cast&d;
因为按照标准
(N3690-§5.2.7-5)
(动态播放)
如果B*是“指向cv1 B的指针”,并且&d具有类型“指向cv2 d的指针”,因此B是d的基类,则结果是指向&d指向的d对象的唯一B子对象的指针
在指针和引用两种情况下,如果cv2的cv限定值大于cv1,或者如果B是D的不可访问或不明确的基类,则程序是格式错误的
总计:3次失败的强制转换(一次抛出异常),
bp = dynamic_cast<B*>(ap);
ap = dynamic_cast<A*>(&d);
bp = dynamic_cast<B*>(&d);
B* bp = (B*)&d;
A* ap = &d;
D& dr = dynamic_cast<D&>(*bp); // This is a runtime error
ap = dynamic_cast<A*>(bp); // this is a runtime error
bp = dynamic_cast<B*>(ap); // this is a runtime error
ap = dynamic_cast<A*>(&d); // succeeds
bp = dynamic_cast<B*>(&d); // This is ill-formed and the compiler should warn about it