C++类对象内存映射

Bru*_*uce 7 c++

当我们创建一个类的对象时,它的内存映射是什么样的.我对对象如何调用非虚拟成员函数更感兴趣.编译器是否创建了一个像vtable一样的表,它在所有对象之间共享?

class A
{
public:
  void f0() {}
  int int_in_b1;
};

A * a = new A;
Run Code Online (Sandbox Code Playgroud)

什么是内存地图?

小智 13

你可以想象这段代码:

struct A {
  void f() {}
  int int_in_b1;
};

int main() {
  A a;
  a.f();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

变成以下的东西:

struct A {
  int int_in_b1;
};
void A__f(A* const this) {}

int main() {
  A a;
  A__f(&a);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

调用f是直截了当的,因为它是非虚拟的.(有时对于虚拟调用,如果已知对象的动态类型,则可以避免虚拟调度,因为它在此处.)


一个较长的例子,可以让您了解虚拟功能如何工作或让您感到非常困惑:

struct B {
  virtual void foo() { puts(__func__); }
};
struct D : B {
  virtual void foo() { puts(__func__); }
};

int main() {
  B* a[] = { new B(), new D() };
  a[0]->foo();
  a[1]->foo();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

变成这样的东西:

void B_foo(void) { puts(__func__); }
void D_foo(void) { puts(__func__); }

struct B_VT {
  void (*foo)(void);
}
B_vtable = { B_foo },
D_vtable = { D_foo };

typedef struct B {
  struct B_VT* vt;
} B;
B* new_B(void) {
  B* p = malloc(sizeof(B));
  p->vt = &B_vtable;
  return p;
}

typedef struct D {
  struct B_VT* vt;
} D;
D* new_D(void) {
  D* p = malloc(sizeof(D));
  p->vt = &D_vtable;
  return p;
}

int main() {
  B* a[] = {new_B(), new_D()};
  a[0]->vt->foo();
  a[1]->vt->foo();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

每个对象只有一个vtable指针,您可以向该类添加许多虚拟方法,而不会影响对象大小.(vtable增长了,但每个类存储一次并且不是很大的开销.)请注意,我在这个例子中简化了许多细节,但它确实有效:析构函数没有被解决(这里应该另外是虚拟的),它会泄漏内存,而__func__值会略有不同(它们由编译器为当前函数的名称生成)等等.