Полиморфный указатель на переменные-члены - PullRequest
0 голосов
/ 16 августа 2011

Я пытаюсь использовать указатели на переменные-члены полиморфным способом.

Это работает:

struct Foo
{
   int member0;
   int member1;

   int* getMember( int i )
   {
     static int Foo::* table[2] = { &Foo::member0, &Foo::member1 };
     return &( this->*table[i] );
   }
};

Это не так, поскольку члены не одного типа (BaseClass):

struct Foo
{
   SubClassA member0;
   SubClassB member1;

   BaseClass* getMember( int i )
   {
     static BaseClass Foo::* table[2] = { &Foo::member0, &Foo::member1 };
     return &( this->*table[i] );
   }
};

Ошибка, сообщаемая g ++:

[...] invalid conversion from 'SubClassA Foo::*' to 'BaseClass Foo::*'
[...] invalid conversion from 'SubClassB Foo::*' to 'BaseClass Foo::*'

Есть ли способ заставить эту работу, то есть "вывести" указатель на член своего базового класса?

Ответы [ 3 ]

1 голос
/ 16 августа 2011
BaseClass* getMember(const int i)
{
  switch(i)
  {
  case 0: return &member0;
  case 1: return &member1;
  default: throw <exception>;
  }
}

Для надежности вы должны в любом случае проверить, находится ли i в пределах диапазона или 0 и 1; так что вы можете подумать об этом упрощенном подходе.

1 голос
/ 16 августа 2011

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

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

Вместо указателей на члены вы можете использовать указатели на функции (или функционально-подобные объекты), которые принимают Foo * и возвращают BaseClass *. Вы должны будете сделать отдельную функцию для каждого члена.

0 голосов
/ 16 августа 2011

Самый простой способ сделать это - вообще пропустить указатели на данные членов.

getMember(int i) {
    BaseClass* ptr[2] = { &member0, &member1 };
    return ptr[i];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...