Получение указателя в C ++ для класса, который является частью другого класса с множественным наследованием - PullRequest
0 голосов
/ 29 июля 2011

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

class a1
{
public:
   int a;
   virtual void func()
   {
   }
   // other non virtual functions ...
};

class b1
{
public:
    //no members or virtual functions
    //other non virtual functions ...
};

class a2
{
public:
   int a;
   // ...
};

template < class T1 >
class derived : public T1,
                public a2
{
    int a;
    // ...
};

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

Однако теперь я хочу получить указатель или ссылку от производного (a1), который действительно является указателем или ссылкой для производного типа (b1).

Что я действительно запрашиваю, так это справку о «хорошем» способе выполнения offsetof (), но используя наследование, где я могу получить offsetof () a2, я предполагаю, что это хороший указатель для производного (b1), потому что b1 - пустой класс.

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

Ответы [ 4 ]

2 голосов
/ 29 июля 2011

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

derived<a1>* instance = whatever();
a1* pointer = instance;

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

a1* pointer = static_cast<a1*>(instance);

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

РЕДАКТИРОВАТЬ: Вы отредактировали вопрос, чтобы сказать, что вы хотите привести из производныхчтобы получить,Это невозможно.static_cast и dynamic_cast не поддерживают операции, которые изменяют структуру памяти экземпляров.Настоятельно рекомендуется использовать любую арифметику указателей, потому что вы не можете знать, как компилятор упорядочивает поля данных экземпляров в памяти.

0 голосов
/ 29 июля 2011

Если вы не использовали шаблоны и просто множественное наследование, предполагая, что d является экземпляром типа Derived, но на него ссылаются как на A1, который вы могли бы иметь.

A1* a = new Derived();
Derived* d = (Derived*)a;
B2* b = d;

Шаблон все усложняет, хотя.

0 голосов
/ 29 июля 2011

Если все, что вы хотите сделать, это сэкономить место в памяти для некоторых ваших объектов, то шаблоны, вероятно, не лучший инструмент для этого.

Поскольку b1 пусто derived<b1> не добавляет ничего полезного к a2, так почему бы не использовать простое наследование class a1 : public a2? Вы можете создавать экземпляры объектов из a1 или a2 в зависимости от того, нужны ли вам дополнительные данные, и все они могут быть преобразованы в a2 (например, если вы хотите сохранить их в списке).

0 голосов
/ 29 июля 2011

Имейте класс b1 как базовый класс класса a1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...