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

时间:2015-06-30 21:05:03

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

我试图解决一个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

任何人都可以解释它的输出吗?我认为基指针指向基本部分的一部分,所以它不是对象的真实地址。

感谢。

2 个答案:

答案 0 :(得分:3)

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

但是当它们与c进行比较时,6又分别转换为&c&c,从而指向相同的A*和{{ 1}}子对象。

以下是内存中B*的可能布局:

A

答案 1 :(得分:2)

<强>背景

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

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

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

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

<强>为什么吗

因为当你调用pb-&gt; 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)

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