c++ - 理解 C++ 指向父类/基类的指针

标签 c++ pointers inheritance

有人问我这个面试问题,但我弄错了。 “输出是什么”:我的答案是 135,实际输出是 136。这意味着指向两个父类的指针不相等,即使它们通过了与子类相等的先前测试。 我以为我理解 c++ 指针,但这让我很难解释。虽然我想我知道发生了什么,但我不知道为什么。任何可以提供技术解释的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;
}

最佳答案

也许如果你打印出 papb 会更清楚发生了什么。

std::cout << "A: " << pa << std::endl;
std::cout << "B: " << pb << std::endl;
std::cout << "C: " << &c << std::endl;

main 的末尾运行它给了我

A: 0xbfef54e0
B: 0xbfef54e4
C: 0xbfef54e0

(您的输出可能不同,重要的是它们并不完全相同)

这是因为 C 对象在内存中的表示方式。由于 C 既是 A 又是 B,因此它需要具有来自每个部分的数据成员。 C 的真正布局是这样的(忽略填充):

int    A::m_i;
double B::m_d;
char   C::m_c;

当您将 C* 转换为 A* 时,编译器知道 A 部分从偏移量 0 开始,因此指针值不变。对于 C*B* 它需要偏移 sizeof(int) (加上填充)。此偏移处理是自动为您计算 xy 完成的。对于 z 它被绕过,因为你使用 reinterpret_cast

关于c++ - 理解 C++ 指向父类/基类的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36455992/

相关文章:

c - 当 unsigned int 可以保存任何地址时, uintptr_t 和 unsigned int 有什么区别吗?

c# - 如何在 F# 中实现 C# 接口(interface)?

java - 从其泛型类型参数派生的泛型类

C 程序段错误

C++ - 清理整数输入

c++ - 在 C++ 中使用未声明的列表作为参数

c++ - 如何使用 boost async_read 返回消息没有终止字符和大小?

c - 如何在函数中使用数组指针?

c# - 首先忽略 EF 代码中所有继承对象中的属性

c++ - 'A(tmpVector);' 与 'A tmpVector;' 有什么区别?