2013-07-24 4 views
2

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

Пример:

#include <stdio.h> 

class A { 
public: 
    int i; 
    int j; 
    void foo(void) { }; 
}; 


int main() 
{ 
    int A::*ptr_j = &A::j; 
    void (A::*ptr_f)(void) = &A::foo; 
    printf("Foo::j pointer to data member %p\r\n", ptr_j); 
    printf("Foo::foo pointer to function member %p\r\n", ptr_f); 
} 

В результате

Foo::j указатель на данные членом 0x4

Foo::foo указатель на функцию член 0x804844c

От «Язык программирования C++ По Страуструпом»,

Указатель на член ... больше похоже на смещение в структуре или индекс в массиве ...

Для данных член, я понимаю, что Pointer-To-Member Foo::j более или менее эквивалентен offsetOf(Foo, j). Значение при использовании gcc-компилятора в моей среде-хосте составляет 4, и оно соответствует тому, что offsetOf(Foo, j) равно 4.

Для члена функции возвращаемое значение равно 0x804844c. И это некоторый адрес, который принадлежит к глобальной области данных

Так что мой вопрос (где загружается класс?):

Что такое «объект», который является адресом 0x804844c.

  1. Это не может быть простой offsetOf(), так как это большое смещение.
  2. Это не может быть адрес vtbl (или адрес записи в vtbl), потому что я верю, что vbtl - это объект, связанный с экземпляром объекта, а не с классом.
  3. Это не может быть адрес, в котором загружен код реализации функции. Поскольку один и тот же указатель может вести себя полиморфно при применении с производным объектом.

Тогда что объект по адресу 0x804844c, и какова ее роль в переводе члена-функции указатель на в фактический адрес функции, когда оператор ->* или .* применяется?

+2

Функции не являются «объектами» в смысле языка С ++, который использует этот термин. Обратите внимание, что функции-члены обычно реализуются как обычные функции с дополнительным параметром (объект становится «этим»). В этих реализациях они не находятся внутри самого экземпляра класса, но наряду с другими (свободными) функциями в сегменте кода. – dyp

+0

* «Это не может быть адрес, где загружается код реализации функции. Поскольку один и тот же указатель может вести себя полиморфно при применении с производным объектом». * См. [этот ответ] (http://stackoverflow.com/a/1087671/420683) – dyp

ответ

3

Вы не можете печатать значения объектов с указателем на элемент с использованием спецификатора преобразования %pprintf. Они не обязательно являются правильными указателями. Спецификатор %p требует значения void *. Строго говоря, вы даже не можете печатать обычный указатель функции с %p, потому что для этого требуется преобразование указателя функции в void *.

Типы указателей на элементы не обязательно вписываются в одно машинное слово, которое может содержать адрес. Они могут быть структурами данных с несколькими полями.

Я верю, что vbtl - это объект, связанный с экземпляром объекта, а не с классом.

Это неверное описание. Виртуальные таблицы являются статическими структурами, и экземпляры указывают только на них. Все экземпляры данного класса имеют указатель на одну и ту же таблицу.

Указатель на нестационарную функцию-член проще в одном отношении, поскольку ему не нужно иметь дело со смещением произвольного элемента данных в экземпляре класса. Однако указатель на нестационарную функцию-член усложняется необходимостью поддержки виртуальных функций и тем фактом, что код, который вызывает такой указатель, не знает или не заботится о том, вызывает ли он виртуальную или не виртуальную функцию ,

Одна стратегия реализации для указателей на функции-члены включает в себя thunks: части кода, сгенерированные компилятором, которые выполняют правильную логику для правильного вызова. Затем указатель на член может указывать на thunk. Thunk знает, где в объекте this найти указатель vtable, а какое смещение в vtable - это функция, которая в конечном счете должна быть вызвана.

Смежные вопросы