Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 失败和格式错误的强制转换_C++_Casting - Fatal编程技术网

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