Как указатели на элементы данных размещаются / хранятся в памяти?

Это одна тема, которая не имеет смысла для меня. Указатели на данные-члены класса могут быть объявлены и использованы. Тем не мение,

  1. Какая логика поддерживает идею? [Я не говорю о синтаксисе, но логика этой функции]

  2. Кроме того, если я правильно понимаю, это будет означать, что при инициализации указателя выделяется неопределенное / переменное количество памяти, поскольку в это время может существовать любое количество объектов. Кроме того, новые объекты могут быть созданы и уничтожены во время выполнения. Следовательно, в действительности, один оператор вызовет большое количество выделений / освобождений. Это кажется довольно нелогичным по сравнению с остальной частью языка. Или мое понимание этого неверно? Я не думаю, что есть какой-либо другой оператор инициализации, который неявно повлияет на выполнение программы так же широко, как это.

  3. Наконец, как распределяется память для этих указателей? Где они расположены относительно объектов? Можно ли увидеть адреса физической памяти этих указателей?

1

Решение

Одно объявление указателя на член данных создает указатели для каждого объекта этого класса.

Нет. Он создает указатель на член (который может быть как смещение от основания объекта)
Затем вы можете использовать его с указателем на объект, чтобы получить этот член.

struct S
{
int  x;
int  y;
};

int S::*  ptrToMember = &S::x;  // Pointer to a member.

S   obj;
int*      ptrToData   = &obj.x; // Pointer to object
// that happens to be a member

Обратите внимание, что при создании указателя на член мы не используем объект (мы просто используем информацию о типе). Таким образом, этот указатель является смещением в классе для получения определенного члена.

Вы можете получить доступ к элементу данных через указатель или объект.

(obj.*ptrToMember)   = 5;   // Assign via pointer to member (requires an object)
*ptrToData           = 6;   // Assign via pointer already points at object.

Почему это происходит, а не создается один указатель, указывающий только на один конкретный экземпляр класса?

Это называется указателем.
Аналогичная, но параллельная концепция (см. Выше).

Какая логика поддерживает идею?

Глупый пример:

 void addOneToMember(S& obj, int S::* member) { (obj.*member) += 1; }

void addOneToX(S& obj)    { addOneToMember(obj, &Obj::x);}
void addOneToY(S& obj)    { addOneToMember(obj, &Obj::y);}

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

Нет. Потому что указатель на член — это просто смещение объекта. Вам все еще нужен фактический объект, чтобы получить значение.

Наконец, как распределяется память для этих указателей?

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

Можно ли увидеть адреса физической памяти этих указателей?

Конечно. Они такие же, как и другие объекты.

 // Not that this will provide anything meaningful.
std::cout.write(reinterpret_cast<char*>(&ptrToMember), sizeof(ptrToMember));

// 1) take the address of the pointer to member.
// 2) cast to char* as required by write.
// 3) pass the size of the pointer to member

// and you should write the values printed out.
// Note the values may be non printable but I am sure you can work with that
// Also note the meaning is not useful to you as it is compiler dependent.
2

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

Одно объявление указателя на член данных создает указатели для каждого объекта этого класса.

Нет. Указатель на член — это специальный объект, который сильно отличается от указателя; это намного больше похоже на смещение. Имея указатель на объект класса и указатель на член, вы сможете получить значение члена; без указателя на объект класса указатель на член бесполезен.

Вопросы 2 и 3 вытекают из одного и того же основного недоразумения.

3

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

0