Структура памяти объекта C ++

Я пытаюсь понять расположение объектов для C ++ в множественном наследовании.
Для этого у меня есть два суперкласса A, B и один подкласс C.
То, что я ожидал увидеть при попытке сброса, было:
vfptr | поля А | vfptr | поля B | поля С.

Я получаю эту модель, но с некоторыми нулями, которые я не понимаю.
Вот код, который я пытаюсь

    #include <iostream>

using namespace std;

class A{
public:
int a;
A(){ a = 5; }
virtual void foo(){ }
};

class B{
public:
int b;
B(){ b = 10; }
virtual void foo2(){ }
};

class C : public A, public B{
public:
int c;
C(){ c = 15; a = 20;}
virtual void foo2(){ cout << "Heeello!\n";}
};

int main()
{
C c;
int *ptr;

ptr = (int *)&c;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;
ptr++;
cout << *ptr << endl;

return 0;
}

И вот результат, который я получаю:

4198384     //vfptr
0
20          // value of a
0
4198416     //vfptr
0
10          // value of b
15          // value of c

В чем смысл нулей между ними?
Заранее спасибо!

2

Решение

Это зависит от вашего компилятора. С clang-500 я получаю:

191787296
1
20
0
191787328
1
10
15
1785512560

Я уверен, что есть способ GDB, но это то, что я получу, если я дам дамп слов размером с указатель с LLDB по адресу объекта класса:

0x7fff5fbff9d0: 0x0000000100002120 vtable for C + 16
0x7fff5fbff9d8: 0x0000000000000014
0x7fff5fbff9e0: 0x0000000100002140 vtable for C + 48
0x7fff5fbff9e8: 0x0000000f0000000a

Это расположение кажется разумным, верно? Как раз то, что вы ожидаете.
Причина того, что в вашей программе это выглядит не так чисто, как в отладчике, заключается в том, что вы сбрасываете слова размера int. В 64-битной системе sizeof (int) == 4, но sizeof (void *) == 8

Итак, вы видите, что ваши указатели разбиты на (int, int) пары. В Linux ваши указатели не имеют битов, установленных ниже 32, в OSX мои указатели делают — следовательно, причина дисбаланса 0 против 1

2

Другие решения

это в значительной степени зависит от архитектуры и компилятора … Возможно, для вас размер указателя может не соответствовать размеру int … Какую архитектуру / компилятор вы используете?

2

Если вы работаете в 64-битной системе, то:

  • Первый ноль — это 4 старших байта первого vfptr,

  • Второй ноль является дополнением, так что второй vfptr будет выровнен по 8-байтовому адресу.

  • Третий ноль — 4 старших байта второго vfptr,

Вы можете проверить, если sizeof(void*) == 8 чтобы утверждать это.

2

Трудно сказать, не зная вашей платформы и компилятора, но это может быть проблемой выравнивания. По сути, компилятор может попытаться выровнять данные класса по 8-байтовым границам с нулями, используемыми для заполнения.

Без вышеперечисленных деталей это всего лишь домыслы.

1

Это полностью зависит от вашего компилятора, системы, битности.

Указатель виртуальной таблицы будет иметь размер указателя. Это зависит от того, компилируете ли вы файл как 32-битный или 64-битный. Указатели также будут выровнены по нескольким адресам их размера (как обычно бывает у любого типа). Вероятно, поэтому вы видите заполнение 0 после 20,

Целые числа будут иметь размер целого числа в вашей конкретной системе. Обычно это всегда 32-битный. Обратите внимание, что если это не так на вашем компьютере, вы получите неожиданные результаты, потому что вы увеличиваете свой ptr на sizeof (int) с помощью арифметики с указателями.

1

Если вы используете MVSC, вы можете сбросить всю структуру памяти всех классов в вашем решении с -d1reportAllClassLayout следующим образом:

cl -d1reportAllClassLayout main.cpp

Надеюсь, что это полезно для вас

1
По вопросам рекламы [email protected]