c++ - 当我将来自 C++ 派生类的指针分配给一个指针时,地址发生了变化
问题描述
我是 C++ 的新手,我正在试验多态性。我有以下代码:
#include <iostream>
class Base1
{
protected:
int b1;
public:
int m() { return 1; }
};
class Base2
{
protected:
int b2;
public:
int n() { return 2; }
};
class Der : public Base1, public Base2
{
protected:
int d1;
public:
int m() { return 11; }
int n() { return 21; }
};
int main()
{
Der *ptr = new Der();
Base1 *b1 = ptr;
Base2 *b2 = ptr;
std::cout << "d: " << ptr << ", m: " << ptr->m() << ", n: " << ptr->n() << "\n";
std::cout << "b1: " << b1 << ", m: " << b1->m() << "\n";
std::cout << "b2: " << b2 << ", n: " << b2->n() << "\n";
delete ptr;
return 0;
}
当我运行这段代码时,有趣的是 b2 被移动了 4 个字节,这里是我的输出:
d: 0x564eab6cbeb0, m: 11, n: 21
b1: 0x564eab6cbeb0, m: 1
b2: 0x564eab6cbeb4, n: 2
为什么这只发生在 b2 上?我想这与事物如何存储在内存中有关,因为如果我删除 b1 b2 中的 int 字段,则不会受到影响。有没有办法轻松查看堆栈和堆?我想看看会发生什么。(我正在使用虚拟工作室代码)
解决方案
OP的示例(简化了一点)
struct Base1 {
int b1;
};
struct Base2 {
int b2;
};
struct Der: Base1, Base2 { };
可能会导致以下内存布局:
// start of Der
// start of Base1
0000: Base1::b1 // type int
// start of Base2
0004: Base2::b2 // type int
因此,当struct Der
被实例化时,其内容的一部分是一个实例,struct Base2
但它不是从Der
实例的同一地址开始的。
和
Der *ptr = new Der();
初始化
Base2 *b2 = ptr;
不会在ptr
to中生成地址的普通副本b2
。也有一个隐含的从Der*
到所Base2*
涉及的转换。编译器知道类Der
和Base2
. 因此,转换导致无提示添加 in 的偏移Base2
量Der
。
为了展示这一点,我做了一个小演示。(我不确定它有多令人信服。):
#include <iostream>
struct Base1 {
int b1 = 1;
};
struct Base2 {
int b2 = 2;
};
struct Der: Base1, Base2 { };
int main()
{
Der *ptr = new Der;
Base2 *b2;
std::cout << "ptr:" << ptr << ", ptr1->b2: " << ptr->b2 << '\n';
b2 = ptr;
std::cout << "b2: " << b2 << ", b2->b2: " << b2->b2 << '\n';
}
使用 gcc 4.1.2 编译,您可以在实际分配发生的位置找到以下代码:
mov %rax, QWORD PTR [%rbp-24] # %rbp-24 <- storage of ptr on stack
add %rax, 4
mov QWORD PTR [%rbp-32], %rax # %rbp-32 <- storage of b2 on stack
笔记:
使用大多数现代编译器版本进行编译会发出类似的add
命令,但也会发出许多其他东西,这些东西不像旧版本的生成代码那么容易(肉眼)破译。因此,我选择了gcc
我能找到的最古老的。
推荐阅读
- node.js - 如何在 Graphql 中删除自省查询的身份验证
- sql - 比较 2 个表(基于辅助表插入、更新或删除)
- javascript - 从 api pull 映射后无法访问数组中的数据
- javascript - 如何让我的服务器返回正确的 Sec-WebSocket-Accept 标头值?
- javascript - 如何打开一个 div,然后单击将一个 div 添加到列表中的下一个项目
- javascript - 在反应中遇到此引导标头问题
- php - 无法在 laravel 项目中使用除 root 以外的任何用户
- python - 如何找到最小长度为 3 的所有可能连续且不重叠的子列表
- c++ - 没有默认构造函数的继承?
- django - 在Django中,按钮url被意外调用,url请求执行方式不同