为什么 static_cast 为同一对象提供不同的内存位置?
Why does static_cast gives different memory locations for same object?
我的代码
class Parent { int a; };
class Child { int b; };
struct GrandChild : public Parent, public Child { int a, b, c; };
int main() {
GrandChild GC;
std::cout << "GrandChild's address is at : " <<&GC<<endl;
std::cout << "Child's address is at : " <<static_cast<Child*>(&GC)<<endl;
std::cout << "Parent's address is at : " <<static_cast<Parent*>(&GC)<<endl;
}
输出:
GrandChild's address is at : 0077F6F8
Child's address is at : 0077F6FC
Parent's address is at : 0077F6F8
为什么 static_cast 之后内存位置会像上面那样不一致?
&GC
是GrandChild
对象GC
的地址。 static_cast<Child*>(&GC)
是 GC
的 Child
子对象 的地址。而static_cast<Parent*>(&GC)
是GC
的Parent
子对象的地址。
在您的特定实现中,GrandChild
对象似乎以 Parent
子对象开头,然后是 Child
子对象,因此 Parent
子对象的地址与完整 GrandChild
对象的地址相同,但是 Child
子对象的第一个字节是 而不是 完整 GrandChild
对象的第一个字节,所以它的地址更高。但是,您不能 依赖这种可移植的行为;不同的实现可能会以不同的顺序分配基 class 和成员子对象,甚至不需要在不同的 class 之间保持一致。
在您的示例中,即使它是实现定义的,它也是可预测的(但允许实现者为简单情况选择直接解决方案:-))
这是您的对象的内存表示(从地址推导出来,而不是从标准推导出来!):
Parent::a (int = 4 bytes)
Child::b (int = 4 bytes)
GrandChild::a
GrandChild::b
GrandChild::c
这是因为您的声明:GrandChild
首先继承自 Parent
,其次继承自 Child
。通过这种表示,Parent
的地址与 GrandChild
的地址相同,而 Child
的地址大 4 是有意义的。
另请注意 GrandChild::a
是 而不是 Parent::a
...
看来这取决于 GrandChild 从 Parent 和 Child 继承的顺序。
通过以下顺序我得到了
struct GrandChild : public Parent, public Child { int a, b, c; };
输出 1:GrandChilds 的地址与 Parent 的地址相同
GrandChild's address is at : 0x22fecc
Child's address is at : 0x22fed0
Parent's address is at : 0x22fecc
关于将 GrandChild 从 Child 和 Parent 继承的顺序更改为
struct GrandChild : public Child , public Parent { int a, b, c; };
输出 2:GrandChilds 的地址与 Child 的地址相同
GrandChild's address is at : 0x22fecc
Child's address is at : 0x22fecc
Parent's address is at : 0x22fed0
GrandChild
派生自 Parent
和 Child
。因此,内存中的 GrandChild
对象由内存中的 Parent
对象和 Child
对象组成。
&GC
本身returns整个GrandChild
对象的内存地址
static_cast<Parent*>(&GC)
returns GrandChild
对象中 Parent
部分的起始地址。
static_cast<Child*>(&GC)
returns GrandChild
对象中 Child
部分的起始地址。
在您的例子中,Grandchild
首先派生自 Parent
,因此 Parent
部分在 GrandChild
的内存块的开头对齐。然后 Child
部分跟在 Parent
部分之后。这是一个说明:
这里的其他答案已经完美地完成了工作,但无论如何让我打扰。
首先,Parent 不是 parent 并且 Child 不是 Parent 的 child...;因为它没有继承自 Parent。 Parent和Child都是GrandParent的继承,不是...grandparent!
其次回答你的问题,你观察到的影响并不是真正的不一致,而是C++如何实现多态性。 (我认为其他答案并没有说明这一点)。
PolyMorphism(poly = many,morphism = morphing into),是一种面向 object 的编程概念,它允许一个 object 能够变形为许多不同的 object运行。这允许 object 表现不同。比如现在是狗,下是猫,后来是鬼。
在大多数面向 object 的语言、C++、Java 等语言中,多态性是如何通过指针算法(递增)和继承来实现的。如果 std::string 可以变形为 std::vector,那会很酷,但是因为它们不共享继承,所以在语法上是不可能的。
然而,对于您的 Parent class,它可以变形为 GrandParent 或任何其他派生的 class。类似地,GrandParent 可以变形为 Parent 或 Child.
多态的另一个名称是多态转换!!!
根据您的问题,理解多态性是一种 C++ 转换很重要。 C++ 转换被设计为准确无损。例如,您可以将 int 转换为 char 并返回。数据的完整性得到维护!同样,如果我要从 GrandParent 转换为 Child(这就是 static_cast 所做的);最好将object的指针设置为Child的地址。如果我们转换为 child 并继续从 GrandParent 读取,那么我们将读取错误的数据。在您首先从 Parent 继承的情况下,我们最终会读取存储在 Parent.
中的 a 和 b 值
更糟糕和更明显的是,这种转换是错误的。如果我们转换为 Child,而 child 有一个特殊的函数,例如 getString,如果我们从 GrandChild 的起始地址调用这个函数,BOOM!我们肯定会遇到运行时崩溃!
希望您喜欢这个视频并学到一些东西。如果你想要更多免费视频记得点赞和订阅。谢谢。
我的代码
class Parent { int a; };
class Child { int b; };
struct GrandChild : public Parent, public Child { int a, b, c; };
int main() {
GrandChild GC;
std::cout << "GrandChild's address is at : " <<&GC<<endl;
std::cout << "Child's address is at : " <<static_cast<Child*>(&GC)<<endl;
std::cout << "Parent's address is at : " <<static_cast<Parent*>(&GC)<<endl;
}
输出:
GrandChild's address is at : 0077F6F8
Child's address is at : 0077F6FC
Parent's address is at : 0077F6F8
为什么 static_cast 之后内存位置会像上面那样不一致?
&GC
是GrandChild
对象GC
的地址。 static_cast<Child*>(&GC)
是 GC
的 Child
子对象 的地址。而static_cast<Parent*>(&GC)
是GC
的Parent
子对象的地址。
在您的特定实现中,GrandChild
对象似乎以 Parent
子对象开头,然后是 Child
子对象,因此 Parent
子对象的地址与完整 GrandChild
对象的地址相同,但是 Child
子对象的第一个字节是 而不是 完整 GrandChild
对象的第一个字节,所以它的地址更高。但是,您不能 依赖这种可移植的行为;不同的实现可能会以不同的顺序分配基 class 和成员子对象,甚至不需要在不同的 class 之间保持一致。
在您的示例中,即使它是实现定义的,它也是可预测的(但允许实现者为简单情况选择直接解决方案:-))
这是您的对象的内存表示(从地址推导出来,而不是从标准推导出来!):
Parent::a (int = 4 bytes)
Child::b (int = 4 bytes)
GrandChild::a
GrandChild::b
GrandChild::c
这是因为您的声明:GrandChild
首先继承自 Parent
,其次继承自 Child
。通过这种表示,Parent
的地址与 GrandChild
的地址相同,而 Child
的地址大 4 是有意义的。
另请注意 GrandChild::a
是 而不是 Parent::a
...
看来这取决于 GrandChild 从 Parent 和 Child 继承的顺序。
通过以下顺序我得到了
struct GrandChild : public Parent, public Child { int a, b, c; };
输出 1:GrandChilds 的地址与 Parent 的地址相同
GrandChild's address is at : 0x22fecc
Child's address is at : 0x22fed0
Parent's address is at : 0x22fecc
关于将 GrandChild 从 Child 和 Parent 继承的顺序更改为
struct GrandChild : public Child , public Parent { int a, b, c; };
输出 2:GrandChilds 的地址与 Child 的地址相同
GrandChild's address is at : 0x22fecc
Child's address is at : 0x22fecc
Parent's address is at : 0x22fed0
GrandChild
派生自 Parent
和 Child
。因此,内存中的 GrandChild
对象由内存中的 Parent
对象和 Child
对象组成。
&GC
本身returns整个GrandChild
对象的内存地址
static_cast<Parent*>(&GC)
returns GrandChild
对象中 Parent
部分的起始地址。
static_cast<Child*>(&GC)
returns GrandChild
对象中 Child
部分的起始地址。
在您的例子中,Grandchild
首先派生自 Parent
,因此 Parent
部分在 GrandChild
的内存块的开头对齐。然后 Child
部分跟在 Parent
部分之后。这是一个说明:
这里的其他答案已经完美地完成了工作,但无论如何让我打扰。
首先,Parent 不是 parent 并且 Child 不是 Parent 的 child...;因为它没有继承自 Parent。 Parent和Child都是GrandParent的继承,不是...grandparent!
其次回答你的问题,你观察到的影响并不是真正的不一致,而是C++如何实现多态性。 (我认为其他答案并没有说明这一点)。
PolyMorphism(poly = many,morphism = morphing into),是一种面向 object 的编程概念,它允许一个 object 能够变形为许多不同的 object运行。这允许 object 表现不同。比如现在是狗,下是猫,后来是鬼。
在大多数面向 object 的语言、C++、Java 等语言中,多态性是如何通过指针算法(递增)和继承来实现的。如果 std::string 可以变形为 std::vector,那会很酷,但是因为它们不共享继承,所以在语法上是不可能的。
然而,对于您的 Parent class,它可以变形为 GrandParent 或任何其他派生的 class。类似地,GrandParent 可以变形为 Parent 或 Child.
多态的另一个名称是多态转换!!!
根据您的问题,理解多态性是一种 C++ 转换很重要。 C++ 转换被设计为准确无损。例如,您可以将 int 转换为 char 并返回。数据的完整性得到维护!同样,如果我要从 GrandParent 转换为 Child(这就是 static_cast 所做的);最好将object的指针设置为Child的地址。如果我们转换为 child 并继续从 GrandParent 读取,那么我们将读取错误的数据。在您首先从 Parent 继承的情况下,我们最终会读取存储在 Parent.
中的 a 和 b 值更糟糕和更明显的是,这种转换是错误的。如果我们转换为 Child,而 child 有一个特殊的函数,例如 getString,如果我们从 GrandChild 的起始地址调用这个函数,BOOM!我们肯定会遇到运行时崩溃!
希望您喜欢这个视频并学到一些东西。如果你想要更多免费视频记得点赞和订阅。谢谢。