为什么static_cast为同一个对象提供不同的内存位置?

问题描述 投票:3回答:5

我的代码

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之后内存位置有如上所述的不一致?

c++ inheritance memory-address static-cast
5个回答
12
投票

GrandChild来自ParentChild。因此,内存中的GrandChild对象由Parent对象和其内存中的Child对象组成。

&GC本身返回整个GrandChild对象的内存地址

static_cast<Parent*>(&GC)返回Parent对象内的GrandChild部分的起始地址。

static_cast<Child*>(&GC)返回Child对象内的GrandChild部分的起始地址。

在你的情况下,Grandchild首先来自Parent,所以Parent部分在GrandChild的记忆块的开头对齐。然后Child部分跟随Parent部分。以下是一个说明:

structure


5
投票

&GCGrandChild对象GC的地址。 static_cast<Child*>(&GC)Child GC子对象的地址。而static_cast<Parent*>(&GC)Parent GC子对象的地址。

在你的特定实现中,似乎GrandChild对象以Parent子对象开始,然后是Child子对象,因此Parent子对象的地址与完整的GrandChild对象的地址相同,但Child子对象的第一个字节不是第一个字节完整的GrandChild对象,所以它的地址更高。但是,您不能依赖这种可移植的行为;不同的实现可以以不同的顺序分配基类和成员子对象,甚至不需要在不同的类之间保持一致。


2
投票

在您的示例中,即使它是实现定义也是可预测的(但是允许实现者为简单情况选择直接解决方案:-))

这是您的对象的内存表示(从地址推断,而不是从标准推断!):

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 ...


0
投票

它似乎取决于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

0
投票

这里的其他答案完美地完成了这项工作,但无论如何让我烦心。

首先,父母不是父母,孩子不是父母的孩子;因为它没有从Parent继承。父母和孩子都是GrandParent的继承,这不是一个伟大的父母!

其次回答你的问题,你观察到的效果并不是真正的不一致,而是C ++如何实现多态性。 (我不认为其他答案是明确的)。

PolyMorphism(poly = many,morphism = morphing into)是一种面向对象的编程概念,它允许一个对象在运行时能够变形为许多不同的对象。这允许对象表现不同。例如,它可以是现在的狗,接下来的猫和后来的鬼。

在大多数面向对象语言(C ++,Java等)中如何实现多态性是通过指针算法(递增)和继承来实现的。如果std :: string可以变形为std :: vector会很酷,但因为它们不共享继承,所以它在语法上是不可能的。

但是在您的Parent类的情况下,它可以变换为GrandParent或任何其他派生类。同样,GrandParent可以变身为父母或儿童。

多态的另一个名称是多态转换!!!

根据您的问题,了解多态性是一种C ++转换非常重要。 C ++转换旨在准确无损。例如,您可以将int转换为char并返回。数据的完整性得到维护!同样,如果我从GrandParent转换为Child(这是static_cast的作用);最好将对象的指针设置为Child的地址。如果我们转换为child并继续从GrandParent读取,那么我们将阅读WRONG DATA。在您首先从Parent继承的情况下,我们最终将读取存储在Parent中的a和b值。

更糟糕,更明显的是,这种转换是错误的。如果我们转换为Child,并且child有一个名为getString的特殊函数,例如,如果我们从GrandChild的起始地址调用此函数,那么BOOM!我们肯定会遇到运行时崩溃!

希望你喜欢这个视频并学到一些东西。如果您想要更多免费视频,请记得喜欢和订阅。谢谢。

© www.soinside.com 2019 - 2024. All rights reserved.