Страница 1 из 1

Почему нельзя получить шестнадцатеричное значение указателя

Добавлено: 21 июн 2004, 03:04
BreakPointMAN
Почему нельзя получить шестнадцатеричное значение указателя на метод класса?
В книге Павловской Т.А. "Программирование на языке высокого уровня" этому дается следующее объяснение: "...в отличие от указателя на переменную или обычную функцию, указатель на метод не ссылается на определенный адрес памяти. Он больше похож на индекс в массиве, поскольку задает смещение. Конкретный адрес в памяти получается путем сочетания указателя на метод с указателем на определенный объект".

Но!!! Но ведь методы не дублируются! Копии полей (т.е. компонентных данных) - да, создаются для каждого экземпляра класса свои... Но методы-то! Они хранятся в единственном числе! Если же верить объяснению Павловской Т.А., то: 1) у нас имеется множество дублированных для каждого экземпляра класса методов, либо 2) непонятно тогда, каким образом смещения для методов ЛЮБЫХ объектов класса ОДНИ И ТЕ ЖЕ, хотя они(объекты класса), естественно, в оперативке в разных местах будут лежать...
Более правдоподобным мне кажется, что указатель на метод класса задает адрес в оперативной памяти необходимой нам компонентной функции, а когда мы вызываем ее (через имя объекта или указатель на объект), таким образом мы передаем ей еще и указатель this. И, все-таки, это не объясняет, почему же нельзя получить шестандцатеричное значение указателя на метод класса...
Так как же все на самом деле?

Добавлено: 21 июн 2004, 11:25
arris
Прости, что мне так показалось, но, по моему, это просто блеск знаний или что-то в этом роде. Скажи, а для чего это реально надо?

Добавлено: 21 июн 2004, 11:26
Romeo
На самом деле всё обстоит именно так, как ты и думаешь. То есть методы класса не дублируются, а вызывая метод класса через точку после некого объекта, ты на самом деле генерируешь вызов метода с дополнительным неявным параметром CYourClassName * const this.
Вопросы возникают другие: Почему ты не можешь получить указатель на метод? (Как ты пытался это делать?) Почему он должен быть именно шестнадцатиричный? И вообще кто такой Павловский? :)

Добавлено: 21 июн 2004, 13:29
Andy
Это про COM или про обычные классы??

Добавлено: 28 июн 2004, 09:01
BreakPointMAN
Romeo писал(а):На самом деле всё обстоит именно так, как ты и думаешь. То есть методы класса не дублируются, а вызывая метод класса через точку после некого объекта, ты на самом деле генерируешь вызов метода с дополнительным неявным параметром CYourClassName * const this.
Это мне известно. Интересует же меня несколько иное...
Romeo писал(а): Вопросы возникают другие: Почему ты не можешь получить указатель на метод? (Как ты пытался это делать?) Почему он должен быть именно шестнадцатиричный?
...ммм... наверное, я недостаточно четко сформулировал вопрос. Да, я могу получить указатель на метод, и с помощью этого указателя вызвать необходимую компонентную функцию. Тут трудностей не возникает. Они появляются, когда я пытаюсь узнать численное значение этого указателя - не важно, будет ли это значение шестандцатеричным, десятичным и т.п. Меня интересует, собственно, вот что: ЧТО ЯВЛЯЕТСЯ ЗНАЧЕНИЕМ УКАЗАТЕЛЯ НА МЕТОД КЛАССА? Адрес в памяти этого самого метода? Смещение? (от чего в таком случае?) Смещение какого-нибудь указателя в таблице? (тогда что это за таблица?) ...любой указатель можно привести к типу void*, хотя для того, чтобы получить его значение в большинстве случаев этого делать не требуется(за исключением указателя на char, потому что при попытке вывести его значение напрямую у нас распечататеся строка, адресуемая им). В случае с указателем на метод класса... хмм... это не получилось...
Romeo писал(а): И вообще кто такой Павловский? :)
Не "Павловский", а "Павловская" - Павловская Татьяна Александровна, профессор кафедры информатики и прикладной математики Санкт-Петербургского государственного университета информационных технологий, механики и оптики (СПбГУИТМО), кандидат технических наук в области систем автоматизации проектирования. Автор ряда работ по Си++, одну из которых я и процитировал...

Добавлено: 28 июн 2004, 09:37
Andy
Раз идет разговор про COM.

На все, что находится в памяти можно получить указатель, в т.ч. и на метод. Когда ты вызываешь метод ты грубо говоря (без учета диспинтерфейсов и т.п.) вызываешь функцию по определенному смещению из vtbl. Адрес этой функции вроде как и искомый указатель :)

Добавлено: 28 июн 2004, 21:47
Vasilisk
Павловская полу...права. Она правильно _ставит_ вопрос, но совершенно неправильно _отвечает_ на него.
Ответ на вопрос-то очевиден вполне - достаточно для небольшой программки попросить у
компилятора вывод ассемблерного листинга...Более подробно это в рассылке про COM рассмотрено
http://developing.ru/com/index.html В статье "введение в теорию компиляции и выведение из неё"...

Вкратце всё вот как выглядит. Любой метод - статическая сущность. Метод отличается от свободной функции только
одним - он получает скрытый параметр this, который есть указатель на структуру данных экземпляра класса.
Если есть возможность вычислить адрес функции, то почему нельзя вычислить адрес метода? Тем не менее, вызвать
"так просто" нестатический метод не получается - ему требуется this. Поэтому где-то в недрах MSDN есть примечание,
что указатель на метод - не четыре байта, а восемь. Т.е. не один адрес, а - два... Один из которых - "адрес функции",
а второй - "адрес this". Но указатель на статический метод эквивалентен указателю на свободную функцию, у него ведь нет
this?

Вообще же, ссылка на this экземпляра передаётся через регистр BX, т.е. в терминах языка высокого уровня нестатический
метод не вызвать "вручную", как свободную функцию с дополнительным параметром. А на ассемблере - запросто.

Добавлено: 28 июн 2004, 23:29
Andy
Привожу типовой пример вызова метода из ассемблера (вырезано из документации к MASM32):

... вырезано ...

When the client makes a call to the COM library to create a COM object, it passes in the address where it wants the object pointer to be placed. This initial pointer is generically referred to as "ppv," from the C++ speak "pointer to pointer to (void)," where (void) means an unspecified type. It holds the address of another pointer ("pv"), and this pointer refers to a whole table of pointers, one table entry for each function of the interface.

For example, say we used CoCreateInstance and successfully got an interface pointer ppv, and wanted to see if it supports some other interface. We can call its QueryInterface method and request a new ppv (ppv2, pointer to an Interface) to the other interface (pIID, pointer to a Interface Identifying GUID) we are interested in. In C, QueryInterface has a prototype that would look like so:

(HRESULT) SomeObject::QueryInterface (this:pObject, IID:pGUID, ppv2:pInterface)


Such a call would look like this:

; get pointer to the object
mov eax, ppv
; and use it to find the interface structure
mov edx, [eax]

; push the function parameters onto the stack
push OFFSET ppv2
push OFFSET IID_ISomeOtherInterface
push dword ppv

; and then call that method
call dword ptr [edx + 0]

... вырезано ...
Пояснения от меня:
1)edx + 0 - это намек на то, что в vtbl QueryInterface - первый метод (AddRef уже будет edx + 4, Release edx + 8)
2)dword ptr [edx] - искомое "шестнадцатиричное" :) значение указателя.
3)this как бы учавствует. но косвенно конечно

PS. Павловской - привет :)

Добавлено: 29 июн 2004, 11:19
Romeo
Женщин не стоит подпускать к компьютеру и тем более писать труды по С++ :)