为什么 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 之后内存位置会像上面那样不一致?

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

在您的特定实现中,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 派生自 ParentChild。因此,内存中的 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!我们肯定会遇到运行时崩溃!

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