Pointer to member question

$4.11/2 states -

An rvalue of type “pointer to member of B of type cv T,” where B is a class type, can be converted to an rvalue of type “pointer to member of D of type cv T,” where D is a derived class (clause 10) of B. If B is an inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this conversion is ill-formed.

My question is why we have the restriction of B not being a virtual base class of D?

7
задан In silico 17 August 2010 в 11:18
поделиться

3 ответа

Рассмотрим ситуацию с невиртуальным базовым классом:

class A { int a; }
class B : public A { int b; }
class C : public A { int c; }
class D : public B, public C { int d; }

Вот возможная структура памяти:

+-------------+
| A: int a;   |
+-------------+
| B: int b;   |
+-------------+
| A: int a;   |
+-------------+
| C: int c;   |
+-------------+
| D: int d;   |
+-------------+

D заканчивается двумя подобъектами A , потому что он наследуется от B и C , и каждый из них имеет подобъект A .

Указатели на переменные-члены обычно реализуются как целочисленное смещение от начала объекта. В этом случае целочисленное смещение для int a в объекте A равно нулю. Таким образом, «указатель на int a типа A » может быть просто целочисленным смещением нуля.

Чтобы преобразовать "указатель на int a типа A " в »указатель на int a типа B , "вам просто нужно целочисленное смещение для подобъекта A , расположенного в B (первый подобъект A ).

Чтобы преобразовать указатель на int a типа A «в» указатель на int a типа C , "вам просто нужно целочисленное смещение для подобъекта A , расположенного в C (второй подобъект A ).

Поскольку компилятор знает, где B и C относительно A , компилятор имеет достаточно информации о том, как выполнить понижающее приведение от A ] на B или C .

Теперь рассмотрим ситуацию с виртуальным базовым классом:

struct A { int a; }
struct B : virtual public A { int b; }
struct C : virtual public A { int c; }
struct D : public B, public C { int d; }

Возможная структура памяти:

+-------------+
| B: ptr to A | ---+
|    int b;   |    |
+-------------+    |
| C: ptr to A | ---+
|    int c;   |    |
+-------------+    |
| D: int d;   |    |
+-------------+    |
| A: int a;   | <--+
+-------------+

Виртуальные базовые классы обычно реализуются с помощью B и C (которые виртуально производят from A ) содержат указатель на единственный субъект A . Указатели на подобъект A необходимы, потому что расположение A относительно B и C не является постоянным.

Если бы все, что у нас было, было «указатель на int a типа A ], мы не смогли бы преобразовать его в» указатель на int a типа B ", поскольку расположение подобъектов B и C может изменяться относительно A . A не имеет обратных указателей на B или C , поэтому у нас просто недостаточно информации для работы понижающего преобразования.

5
ответ дан 7 December 2019 в 09:55
поделиться

При невиртуальном наследовании члены базового класса и производного класса могут быть расположены в памяти непрерывно, причем сначала базовый класс, так что каждый член базового класса находится в одном месте относительно адреса объекта. является ли объект B или D . Это упрощает преобразование указателя на член B в указатель на член D ; оба могут быть представлены как смещение от адреса объекта.

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

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

1
ответ дан 7 December 2019 в 09:55
поделиться

Действительно интересный вопрос. Узнал что-то новое сегодня. Вот что я смог найти по теме: Преобразование указателей функций-членов из производного класса в виртуальный базовый класс не работает

0
ответ дан 7 December 2019 в 09:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: