我的代码
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之后内存位置有如上所述的不一致?
答案 0 :(得分:12)
GrandChild
来自Parent
和Child
。因此,内存中的GrandChild
对象在其内存中包含Parent
对象和Child
对象。
&GC
本身返回整个GrandChild
对象的内存地址
static_cast<Parent*>(&GC)
返回Parent
对象中GrandChild
部分的起始地址。
static_cast<Child*>(&GC)
返回Child
对象中GrandChild
部分的起始地址。
在您的情况下,Grandchild
首先从Parent
派生,因此Parent
部分在GrandChild
的内存块的开头对齐。然后Child
部分跟在Parent
部分之后。以下是一个说明:
答案 1 :(得分:5)
&GC
是GrandChild
对象GC
的地址。 static_cast<Child*>(&GC)
是Child
的{{1}} 子对象的地址。 GC
是static_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的起始地址调用此函数!我们肯定会遇到运行时崩溃!
希望您喜欢这个视频并学到一些东西。如果您想要更多免费视频,请记住喜欢并订阅。谢谢。