Указатели на представления участников

Я пытаюсь сделать некоторые обратные вызовы из функций-членов, и все было нормально, пока я не попытался использовать класс шаблона, полученный из 2-х классов, в качестве объекта обратного вызова, когда я получил следующую ошибку:

error C2440: 'reinterpret_cast' : Pointers to members have different representations; cannot cast between them

Эта вещь сигнализировала мне, что указатели функций-членов имеют разные представления (doh!)

Что это за представления? В чем разница между ними?

Ответ 1

Дэнни Калев объясняет это довольно хорошо:

Базовое представление указателей на члены

Хотя указатели на элементы ведут себя как обычные указатели, за кулисами их представление совершенно иное. Фактически, указатель на член обычно состоит из структуры, содержащей до четырех полей в определенных случаях. Это связано с тем, что указатели на члены должны поддерживать не только обычные функции-члены, но также функции виртуальных членов, функции-члены объектов, которые имеют несколько базовых классов, и функции-члены виртуальных базовых классов. Таким образом, простейшая функция-член может быть представлена ​​как набор из двух указателей: один, содержащий физический адрес памяти функции-члена, и второй указатель, который содержит указатель this. Однако в таких случаях, как виртуальная функция-член, множественное наследование и виртуальное наследование, указатель на член должен хранить дополнительную информацию. Таким образом, вы не можете накладывать указатели на участников на обычные указатели и не можете безопасно использовать между указателями для членов разных типов.

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

struct A
{
 int x;
 void f();
};
int A::*pmi = &A::x;
void (A::*pmf)() = &A::f;
int n = sizeof (pmi); // 8 byte with my compiler
int m = sizeof (pmf); // 12 bytes with my compiler

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

Ответ 2

Это вещь Microsoft: в некоторых случаях они уменьшают указатели на функции-члены за счет создания указателей на функции-члены, которые имеют разные представления, как вы только что видели. Есть переключатель, чтобы отключить это (/vmg), чтобы все указатели на элементы имели одинаковое представление.