铸造到不同的基础类别会产生不同的结果.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)<<"nn";
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是不良的设计。我不是在考虑设计,而是困扰我的行为。任何人都可以解释为什么铸造不同的方式第一次给出不同的结果,但第二次相同的结果?
本质上, A
和 B
C
的部分不能占据相同的空间。一个必须在另一个面前。当您将C*
正确施放到A*
时,您将获得一个指向原始指针指向的实例的A
部分的指针,并且施放到B*
也是如此。由于C
的A
部分(int A::n;
(和C
(int B::n;
(的B
部分必然在不同的地址处,因此这些转换的结果自然而然。这是可能的,因为编译器可以知道pc
指向对象的布局,因此可以从其类型中推论信息。如果没有信息,这将行不通,例如,如果指针被施加到void*
。
reinterpret_cast
给出相同地址的原因,无论您使用什么,因为这是reinterpret_cast
所做的。它在忽略任何形式的类型安全性的同时将指针或引用转换为其他类型。对于reinterpret_cast
,指针是创建一个新型指针,其地址与所提供的地址相同,无论实际类型和类型的安全性如何。
提防使用reinterprect_cast
,因为它实际上将事实注入了类型的安全系统。编译器必然会假设您所说的是正确的。如果这些"事实"不是正确的(例如reinterpret_cast<B*>(pc)
的情况(,您就有不确定的行为。
定义类也意味着定义内存布局。以最简单的形式连续布置成员,例如
struct A {
int n;
};
和内存中
| Address | Size | Member |
|----------+------+--------+
| 0042F82C | 4 | n |
基类也发生了同样的事情
struct C : A, B {
};
潜在内存布局
| Address | Size | Member |
|----------+------+--------+
| 0042F82C | 4 | A::n |
| 0042F830 | 4 | B::n |
现在,您有一个指针pc
到类型C
的对象。使用static_cast
考虑了对象中成员和基类的布局。
因此,您获得了A
或B
部分的正确地址。
在另一侧使用reinterpret_cast
,只需重用指针并假装指向另一种类型即可。
说明
与static_cast不同,但是像const_cast一样,reinterpret_cast表达式不会编译到任何CPU指令。它纯粹是一个编译器指令,它指示编译器将表达式的序列(对象表示(处理好,就好像它具有new_type。
。
这是原因,为什么您获得相同的地址值。
- 如何返回一个类的两个对象相加的结果
- 你好。。。id_public变量不应该给出结果为 81 和 86 吗?为什么它为两个派生类占用不同的内存位置?
- 为什么static_cast基础类型的枚举类int8_t获得意外值?
- 如何在工厂方法中返回指向基于基础操作系统的派生类的有效指针
- 枚举类的 C 样式强制转换到基础类型 char 的引用
- C++:使用类在向量中搜索特定元素时,我得到了错误的结果
- 类中静态函数C++意外结果
- C ++基础私有方法在将自身转换为派生类后可以访问吗?
- 类(可能是代理)的命名,允许在不修改基础容器的情况下对项目进行排序和删除
- C++ 类型转换基础 PTR 到派生 PTR 保存在引用类中
- 安全地将枚举类从基础类型转换
- 在DelphiInterface上实现Dynamic_cast以获取基础对象类的任何方法
- (重新定义错误)从C 中的一个基础上创建多个Inherting类
- 基础类模板参数的有意义名称
- 为基础类构造函数提供初始化的成员
- C++多态性,关于宣布对派生类的基础类引用
- 具有相同基础类类型的条件运算符
- 基础类的初始派生类
- 基础类指针使用已分配的内存来派生类指针
- 那么,现在用C++11编写的基础类是怎样的呢