为什么pA,pB,pC不相等

Why are pA,pB,pC not equal?

本文关键字:不相等 pC pB 为什么 pA      更新时间:2023-10-16

考虑以下程序

 #include<iostream>
 using namespace std;
 class ClassA
{
public:
    virtual ~ClassA(){};
    virtual void FunctionA(){};
};
class ClassB
{
 public:
    virtual void FunctionB(){};
};

class ClassC : public ClassA,public ClassB
{
};
void main()
{
    ClassC aObject;
    ClassA* pA = &aObject;
    ClassB* pB = &aObject;
    ClassC* pC = &aObject;
    cout<<"pA = "<<pA<<endl;
    cout<<"pB = "<<pB<<endl;
    cout<<"pC = "<<pC<<endl;
}
pA,

pB,pC应该相等,但结果是

pA = 0031FD90

pB = 0031FD94

pC = 0031FD90

为什么 pB = pA + 4?当我改变时

class ClassA
{
public:
    virtual ~ClassA(){};
    virtual void FunctionA(){};
};
class ClassB
{
 public:
    virtual void FunctionB(){};
};

class ClassA
{
};
class ClassB
{
};

结果是

pA = 0030FAA3

pB = 0030FAA4

pC = 0030FAA3

pB = pA + 1?

乘法继承的对象有两个合并的子对象。 我编译器将其中一个指针指向内部对象。

C 有两个继承的子对象,因此是 A 对象和 B 对象的串联。当您有一个对象 C 时,它由一个对象 A 后跟一个对象 B 组成。它们不位于同一地址,这就是原因。所有三个指针都指向同一个对象,但作为不同的超类。编译器会为您进行转换,因此您不必担心。

现在。为什么一种情况有 4 分,另一种情况有 1 分的差异?在第一种情况下,您有 A 和 B 的虚函数,因此每个子对象都必须有一个指向其 vtable 的指针(包含已解析的虚函数调用地址的表)。所以在这种情况下,sizeof(A)是 4。在第二种情况下,您没有虚拟函数,因此没有 vtable。但是每个子对象都必须是可独立寻址的,因此编译器仍然必须为 A 类的子对象和类 B 的子对象分配不同的地址。两个地址之间的最小差值为 1。但我想知道在这种情况下是否不应该启动 EBO(空基类优化)。

这是编译器的实现细节。您遇到这种情况的原因是您的代码中有MI

考虑一下计算机如何访问ClassB中的成员,它使用偏移量来访问成员。因此,假设您在类 B 中有两个 int,它使用以下语句访问第二个 int 成员。

  *((int*)pb + 1) // this actually will be assembly generate by compiler

但是,如果pb指向类中aObject的开始,这将不再起作用,因此编译器需要生成多个程序集版本才能访问基于类继承结构的同一成员,并且具有运行时成本。

这就是为什么编译器将 pb 调整为不等于 pa,这将使上面的代码工作,这是最简单和效果的实现方式。

这也解释了为什么pa == pc但不等于pb