对于多态类的对象,对象的地址和指向对象的指针是不是相同?

Posted

技术标签:

【中文标题】对于多态类的对象,对象的地址和指向对象的指针是不是相同?【英文标题】:Are address of object and pointer to object the same thing for an object of polymorph class?对于多态类的对象,对象的地址和指向对象的指针是否相同? 【发布时间】:2015-06-30 21:05:03 【问题描述】:

我试图解决一个 c++ 测试,并看到了这个问题。

#include <iostream>

class A

public:
    A() : m_i(0)  

protected:
    int m_i;
;

class B

public:
    B() : m_d(0.0)  

protected:
    double m_d;
;

class C
    : public A
    , public B

public:
    C() : m_c('a')  

private:
    char m_c;
;

int main()

    C c;
    A *pa = &c;
    B *pb = &c;

    const int x = (pa == &c) ? 1 : 2;
    const int y = (pb == &c) ? 3 : 4;
    const int z = (reinterpret_cast<char*>(pa) == reinterpret_cast<char*>(pb)) ? 5 : 6;

    std::cout << x << y << z << std::endl;

    return 0;

Output:

136

谁能解释它的输出?我以为基指针指向基部分的一部分,所以它不是对象的真实地址。

谢谢。

【问题讨论】:

添加了输出 - 感谢您提供实际上是 MCVE 的 sn-p :) 【参考方案1】:

pa 指向Ac 子对象。 pb 指向 B 的子对象 c。显然,它们指向内存中的不同位置(因此输出中的 6)。

但是当它们与&amp;c 比较时,&amp;c 再次分别转换为A*B*,从而指向相同的AB 子对象。

这里是为了说明c 在内存中的可能布局:

+------------------------+-------------+-------------------+
| A subobject            | B subobject | Remainder of C    |
+------------------------+-------------+-------------------+
^ &c is here             ^ pb points here
^ pa also points here

【讨论】:

&amp;c分别转换为A*B*,比较子对象地址。除非有人在没有人注意的情况下偷偷潜入魔法隐式向下转换。 你确定这个结构吗?或者这只是一个例子? @molbdnilo 真的!我的错。 @GrigorApoyan 这是编译器在实践中最有可能生成的(假设没有进行虚拟继承)【参考方案2】:

背景

对象 C 在内存中看起来像这样

    -----------  <----- Start of the object
    |    A    |
    |---------|  <----- Beginning of B implementation
    |    B    |
    |---------|
    |    C    |
    |_________|  <----- End of the object

当您从派生类(例如 A* pa = &c)获取指向基类的指针时,该指针指向该对象的该类实现的开头。

所以这意味着 A* 将指向 A 的开头(恰好是对象的开头),而 B* 将指向 B 的开头。请注意,C* 不会指向 C 的开头,因为它知道 C 是从 A 和 B 派生的。它会指向对象的开头。

为什么?

因为当你调用 pb->someFunction() 时,它实际上是获取指向 B 的指针并添加一些预先计算好的偏移量并执行。如果 pb 指向 A 的开头,那么它将在 A 内部结束。预先计算的偏移量是必要的,因为您不知道 pb 实际指向什么(是 C,是“D”,还是只是简单老B?)。这种方法允许我们始终依赖偏移量来查找函数。

这就是您的代码真正在做什么

((A*)pa == (A*)&c) // Obviously true, since we defined it as such above.
((B*)pb == (B*)&c) // Obviously true, since we defined it as such above.
(reinterpret_cast<char*>(pa) == reinterpret_cast<char*>(pb)) // We know pa and pb point to different places in memory. If we cast them both to char*, they will obviously not be equivalent.

一个有趣的尝试是

if (pa == pb)

这会给你一个编译错误,因为你需要将两个指针都转换为一个公共类型。

【讨论】:

以上是关于对于多态类的对象,对象的地址和指向对象的指针是不是相同?的主要内容,如果未能解决你的问题,请参考以下文章

C++学习_多态

java多态实现原理

多态对象的数组

深入C++对象模型&虚函数表

6多态性-3虚函数

关于C++基类、派生类的引用和指针