2

我有一些代码可以访问派生和基础ptrs,当我打印出地址时,它们是相同的。如果是这种情况,编译器如何知道它所指的地址是 A 还是 B?

这是代码:

#include <iostream>

class A
{
public:
   A() : val_(0) {
       ptrA = this;
   }

   virtual void set(int val) { val_ = val; }

   virtual void printval() = 0;

   static A* ptrA;

   int val_;
};

class B : public A
{
public:
   B() : A() {
      ptrB = this;
   }

   virtual void printval() { std::cout << A::val_ << std::endl; }

   static B* ptrB;
};

A* A::ptrA = 0;
B* B::ptrB = 0;

int main() {

   A* p = new B();
   p->set(3);
   p->printval();

   std::cout << "A part address=" << A::ptrA << std::endl;
   std::cout << "B part address=" << B::ptrB << std::endl;

   return 0;
}

这是打印输出:

A part address=00501F40
B part address=00501F40

两个地址完全相同。编译器是否还存储了一些额外的信息?

编辑:是的,我的意思是说程序在运行时如何知道。

4

2 回答 2

2

通过实现依赖机制内置的额外信息。当你编译你的程序时,编译器会悄悄地添加它记录所需的所有代码。
对于几乎所有编译器,动态调度都是通过虚拟表和指针实现的。

食物阅读:

当我调用虚函数时,硬件会发生什么?有多少层间接?有多少开销?

于 2013-03-28T18:28:45.367 回答
0

实际上,假设像你这样的“普通”C实现,B类的大部分数据是一个结构,该结构的第一个成员是A类的对象。因为B和它包含的A都从同一个地方,他们有同一个地址。

因为在 B 的开头有一个 A 对象,所以可以将指向 B 对象的指针转换为指向 A 对象的指针,它的行为类似于 A 对象,因为它是:它是指向 A 数据的指针。

虚函数更复杂。在 A 数据中,您通常看不到,它是一个指向表的指针。如果该对象真的是一个普通的 A 对象,则该指针将指向一个包含 A 的虚函数地址的表。如果该对象是 B 对象,则该指针指向一个包含虚函数地址的表B 的函数。结果是,如果你有一个指针,其编译时类型似乎是指向 A 的指针,编译器会通过在表中查找它们的地址来调用它的函数。如果指向对象的实际类型是 B,则此表提供 B 的虚函数地址。

于 2013-03-28T18:32:33.787 回答