当我将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才会发生这种情况?我想这与事物如何存储在内存中有关,因为如果我删除b1中的int字段,b2不会受到影响。有没有一种方法可以方便地查看堆栈和堆?我想看看会发生什么。(我使用的是虚拟演播室代码)是的,它与事物如何存储在内存中有关 类当我将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; },c++,polymorphism,C++,Polymorphism,为什么只有b2才会发生这种情况?我想这与事物如何存储在内存中有关,因为如果我删除b1中的int字段,b2不会受到影响。有没有一种方法可以方便地查看堆栈和堆?我想看看会发生什么。(我使用的是虚拟演播室代码)是的,它与事物如何存储在内存中有关 类Der包括Base1和Base2作为子对象 看看这个。OP的示例(简化了一点) 可能导致以下内存布局: // start of Der // start of Base1 0000: Base1::b1 // type int // start of Bas
Der
包括Base1
和Base2
作为子对象
看看这个。OP的示例(简化了一点)
可能导致以下内存布局:
// start of Der
// start of Base1
0000: Base1::b1 // type int
// start of Base2
0004: Base2::b2 // type int
因此,当实例化struct Der
时,它的部分内容是struct Base2
的实例,但它不是从Der
实例的相同地址开始的
与
初始化
Base2 *b2 = ptr;
不会导致ptr
到b2
中地址的纯拷贝。还涉及从Der*
到Base2*
的隐式转换。编译器知道类Der
和Base2
之间的关系。因此,转换导致在Der
中对Base2
的偏移量进行无声添加
为了在行动中展示这一点,我制作了一个小演示。(我不确定这有多令人信服):
#包括
结构Base1{
int b1=1;
};
结构Base2{
int b2=2;
};
结构Der:Base1,Base2{};
int main()
{
Der*ptr=新的Der;
碱基2*b2;
STD::你忘记了把虚拟函数添加到你的函数成员,所以你没有使用多态性,你是影子方法,我没有,我尝试用各种方法来实现C++中的某种多态性,虚拟的默认使用java和CRTP方法在Java中发生什么。h我使用虚拟方法我知道派生对象包括基本对象,但我关注的是指针,问题是为什么b1有相同的ptr地址,而b2没有,即使b1=ptr和b2=ptr。我想确定为什么会发生这种情况,并更详细地解释这些变量如何存储在内存中。@GJCode不是ptr
中的地址只需复制到b2
。它还包括从Der*
到Base2*
的隐式(说“静默”)转换,以使b2
成为指向Base2
的正确指针(分配ptr
)编译器知道Der
中Base2
的偏移量,并将偏移量添加到b2
的赋值中。因此,您的意思是:我有一个在内存中看起来像这样的Der对象:[base1(base1\u字段)、Base2(Base2\u字段)、Der(deru字段)]因此,当我执行b2=ptr时,编译器说“ok”,lval的类型是Base2,Der包含一个Base2对象,所以让我们指向它,而不是执行ptr+base1。这是正确的吗?所以我们假设连续分配,并且按照我执行Der时指定的顺序:public base1,public Base2。@GJCode简言之:是的。我添加了一个答案来解释它更长一点。;-)是的这正是我想要的,它完全有道理,我真的很欣赏这些指令生成的汇编代码的细节。谢谢!
// start of Der
// start of Base1
0000: Base1::b1 // type int
// start of Base2
0004: Base2::b2 // type int
Der *ptr = new Der();
Base2 *b2 = ptr;
#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';
}
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