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

时间:2015-08-08 08:10:53

标签: c++ inheritance memory-address static-cast

我的代码

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

5 个答案:

答案 0 :(得分: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

答案 1 :(得分:5)

&GCGrandChild对象GC的地址。 static_cast<Child*>(&GC)Child的{​​{1}} 子对象的地址。 GCstatic_cast<Parent*>(&GC)的{​​{1}} 子对象的地址。

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

答案 2 :(得分: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 ...

答案 3 :(得分: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

答案 4 :(得分: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的起始地址调用此函数!我们肯定会遇到运行时崩溃!

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