投射到不同的 Base 类 会得到不同的结果。 C++

Casting to different Base classes gives different result. C++

也许我的问题不完整,但我的代码会让一切都清楚。

#include <iostream>
using namespace std;

struct A{int n;};
struct B{int n;};
struct C : A, B{};

int main()
{
    C c;
    C* pc = &c;

    std::cout<<"TEST1"<<std::endl;
    cout << static_cast<B*>(pc) << "\n";
    cout << reinterpret_cast<B*>(pc)<<"\n\n";

    std::cout<<"TEST2"<<std::endl;
    cout << static_cast<A*>(pc) << "\n";
    cout << reinterpret_cast<A*>(pc)<<"\n";
}

输出为:

TEST1
0042F830
0042F82C

TEST2
0042F82C
0042F82C

我知道使用 reinterpret_cast 是错误的设计。我不是在考虑设计,但行为才是困扰我的地方。 谁能解释一下为什么第一次使用不同的方式会产生不同的结果,而第二次会产生相同的结果??

本质上,CAB 部分不能占据相同的 space。一个必须先于另一个。当你正确地将 C* 转换为 A* 时,你会得到一个指向原始指针指向的实例的 A 部分的指针,转换为 [= 也是如此16=]。由于CA部分(int A::n;)和CB部分(int B::n;)必然在不同的地址,自然这些转换的结果也彼此不同。这是可能的,因为编译器可以知道 pc 指向的对象的布局,信息可以从它的类型中推断出来。如果信息不可用,这将不起作用,例如,如果指针首先被转换为 void*

reinterpret_cast 给出相同地址而不管您转换为什么的原因是因为 reinterpret_cast 就是这样做的。它将指针或引用转换为另一种类型,同时忽略任何形式的类型安全。 reinterpret_cast 指针是创建一个新类型的指针,其地址与提供的地址相同,而不管实际类型和类型安全性。

小心使用 reinterprect_cast,因为它本质上是将事实注入类型安全系统。编译器一定会假设您告诉它的是正确的。如果那些 "facts" 不正确(例如 reinterpret_cast<B*>(pc) 的情况),您将面临未定义行为的风险。

定义一个class也意味着定义一个内存布局。在最简单的形式中,成员是连续排列的,例如

struct A {
    int n;
};

在记忆中

| Address  | Size | Member |
|----------+------+--------+
| 0042F82C | 4    | n      |

基数 classes

也是如此
struct C : A, B {
};

潜在的内存布局

| Address  | Size | Member |
|----------+------+--------+
| 0042F82C | 4    | A::n   |
| 0042F830 | 4    | B::n   |

现在您有一个指向 C 类型对象的指针 pc。使用 static_cast 考虑了对象中成员和基 classes 的布局。

因此,您得到 AB 部分的正确地址。

另一方面使用reinterpret_cast,只是重用一个指针并假装它指向另一种类型。

Explanation

Unlike static_cast, but like const_cast, the reinterpret_cast expression does not compile to any CPU instructions. It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type.

这就是您获得相同地址值的原因。