【问题标题】: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 :)

标签: c++ pointers inheritance polymorphism multiple-inheritance


【解决方案1】:

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

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

这里是为了说明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)

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

【讨论】:

    猜你喜欢
    • 2023-02-09
    • 2020-02-26
    • 2020-04-14
    • 1970-01-01
    • 2013-03-27
    • 1970-01-01
    • 1970-01-01
    • 2015-05-15
    • 1970-01-01
    相关资源
    最近更新 更多