Преобразование указателя на базовый класс в указатель на производный класс - PullRequest
3 голосов
/ 21 февраля 2012

Я немного прочитал о кастинге в C ++. Исходя из фона C, использование обычного (type) приведения является обычным для таких вещей, как void *, но для C ++ есть dynamic_cast, reinterpret_cast, static_cast и т. Д.

Проблема / вопрос / вопрос в том, какие из приведенных выше приведений следует использовать при преобразовании между базовым указателем и производным указателем.

Наше хранилище данных хранит указатель на базовый класс (B). Функции выделяют производные указатели (D).

Пример кода выглядит следующим образом:

class B
{ int _some_data; }
class D : public B
{ int _some_more_data; }

Код выглядит примерно так:

D *obj = new D;
obj->_some_data = 1;
obj->_some_more_data = 2;
<store obj>

Потом, когда мы получим доступ к данным:

B *objB = <get out data>
if (objB->_some_data == 1)
{ D *objD = (D *) objB; <do some processing> }

Теперь актерский состав, который меня беспокоит, - D *objD = (D *) objB.

Какой бросок мы должны использовать?

Спасибо.

Ответы [ 3 ]

6 голосов
/ 21 февраля 2012

В этом случае ни одно приведение не является действительно безопасным.

Самым безопасным будет dynamic_cast, но ваши объекты не являются полиморфными, поэтому здесь это не применимо.Но вы должны рассмотреть, по крайней мере, наличие деструктора virtual, так как я вижу, что вы планируете расширить классы.

static_cast небезопасно, как указано на этой странице msdn :

class B {};

class D : public B {};

void f(B* pb, D* pd) {
   D* pd2 = static_cast<D*>(pb);   // not safe, pb may
                                   // point to just B

   B* pb2 = static_cast<B*>(pd);   // safe conversion
}

reinterpret_cast также не имеет проверок, поэтому не полагайтесь на него.

Кроме того, приведение к указателю производного класса - это как минимум кодзапах, если вам нужно сделать это, это на 99% уверен, что у вас есть дефектный дизайн.

3 голосов
/ 21 февраля 2012

Для связанных типов, о которых вы знаете, но компилятор не знает, используйте static_cast.

Но в вашем случае вы вообще не должны приводить.

Вы пишете, что

Наше хранилище данных хранит указатель на базовый класс (B).Функции выделяют производные указатели (D).

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

Чтобы использовать поддержку C ++, сделайте B полиморфнымкласс, то есть, по крайней мере, с одним virtual членом:

struct B { virtual ~B() {} };

Я удалил элемент данных _some_data, так как, очевидно, его единственная цель состояла в том, чтобы отслеживать динамический тип, и теперь поддержка C ++ делает этона практике через так называемый «указатель vtable» в объекте.Общий размер объекта, вероятно, одинаков.Однако притяжение клопов и явное уродство уменьшаются на несколько порядков.; -)

Затем,

struct D
    : B
{
    int some_more_data_;
    D( int v ): some_more_data_( v ) {}
};

И затем, с полиморфными классами, ваш код обработки может использовать безопасный dynamic_cast, как показано ниже:

B* const objB = getOutData();
if( D* const objD = dynamic_cast<D*>( objB ) )
{
    // do some processing using objD
}

Теперь эта ручная динамическая проверка типов все еще очень грязная и отражает архитектуру системы без OO.Благодаря объектной ориентации, вместо операций, проверяющих, какие данные им были предоставлены, данные фактически содержат указатели на соответствующие специализированные операции.Но я думаю, что было бы лучше всего делать один шаг за раз, и в качестве первого шага вышеперечисленное: избавиться от хрупкой притягивающей ошибки схемы доморощенной динамической проверки типов и использовать относительно чистую супер-пупер свежую, приятно пахнущую, хорошо выглядящуюПоддержка C ++ для этого.: -)

0 голосов
/ 21 февраля 2012

В этом случае вы должны использовать dynamic_cast.

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