Я искал способ получить доступ к vtable прямо через указатель и наткнулся на это сообщение: http://www.codeproject.com/Tips/90875/Displaying-vtable-when-debugging
Он отлично работает, и я могу вызывать функции через записи vtable. Но мне трудно понять эту линию део:
void (**vt)() = *(void (***)())ptr;
ptr
- указатель на объект. Как я могу расшифровать эту строку и как получить vt
-адрес vt
?
Спасибо.
void (**vt)()
vt - указатель на указатель на некоторую функцию. Эта функция возвращает void и не принимает никаких параметров. void (***)()
означает указатель на указатель на такую функцию (то есть один уровень указателя больше, чем выше).
Во-первых, вы отбрасываете ptr на такой трехуровневый указатель на функцию.
Затем вы получаете то, на что указывает (с единственным *
), то есть двухуровневый указатель на функцию, т.е. тот же тип a переменная vt. Это означает, что вы можете назначить его для vt, и это будет исключительно то, что делает эта строка.
И почему?
В такой переменной x: void(*x)()
может быть сохранен единственный указатель на функцию void-no-param-function. И не совсем связано, если вы хотите передать некоторый массив функции, вы передаете указатель. То есть. достаточно сохранить адрес массива в указателе для доступа к целому массиву (если длина известна).
Это означает, что void(**vt)()
может хранить (адрес) массив указателей на функции.
Vtable - не что иное, просто массив указателей на функции.
Если у вас есть автомобиль класса с некоторыми переменными, такими как цвет и vtable, и он использует, например. 200 байт на объект. Указатель на автомобиль похож на указатель на 200-байтовый массив, и если вы получаете доступ к цвету в коде, компилятор просматривает этот цвет, например. байт 133 и генерирует доступ к нему.
Где vtable находится внутри этого объекта, определяется реализация, но часто в начале. Если у вас есть указатель на автомобиль, это указатель на массив из 200 байт, разделенный на некоторые указатели fucntion и некоторые другие данные после них...
=> Vtable, т.е. массив указателей функций, начинается с начального адреса автомобиля.
=> Если вы указали указатель на указатель на vtable, т.е. указатель на "массив указателей функций", т.е. указатель на "указатель на указатель на функцию" и уважение, что у вас есть массив vtable.
Фактическое местоположение _vtable в объекте зависит от компилятора. Код предполагает, что адрес _vtable сохраняется сначала в объекте (что, по-видимому, все современные компиляторы). Кроме того, существует только один vtable для каждого класса, который хранится в одном месте. Таким образом, каждый экземпляр имеет адрес для этого массива указателей на функции.
В принципе, вы создаете переменную с именем vt, то есть массив указателей на функции, которые возвращают void и не принимают никаких параметров. Затем вы инициализируете эту переменную содержимым, найденным в первом члене объекта (адрес vtable).
(void (***)())ptr
означает, что вы перенесите эту первую 4 (32-битную машину) или 8 (64-разрядную машину) на указатель на массив указателей функций, которые возвращают void и не принимают никаких параметров.
*(void (***)())ptr
возвращает содержимое этих 4 или 8 байтов, то есть адрес vtable.