Подтвердить что ты не робот

Dynamic_cast из "void *"

В соответствии с этим, void* не имеет информации RTTI, поэтому кастинг из void* не является законным и имеет смысл.

Если я правильно помню, dynamic_cast из void* работал над gcc.

Можете ли вы прояснить проблему.

4b9b3361

Ответ 1

dynamic_cast работает только с полиморфными типами, то есть с классами, содержащими виртуальные функции.

В gcc вы можете dynamic_cast на void*, но не из:

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

int main()
{
    S* p = new S();
    void* v = dynamic_cast<void*>(p);
    S* p1 = dynamic_cast<S*>(v); // gives an error
}

Ответ 2

В 5.2.7 - Dynamic cast [expr.dynamic.cast] говорится, что для dynamic_cast<T>(v):

  • Если T - тип указателя, v должен быть rзначением указателя на полный тип класса
  • Если T является ссылочным типом, v должен быть lvalue полного типа класса (спасибо usta за комментарий к моему отсутствующему этому)

...

  • В противном случае v должен быть указателем на или значением полиморфного типа

Итак, нет, значение (void*) не разрешено.

Подумайте о том, что может означать ваш запрос: скажем, у вас есть указатель, который действительно соответствует Derived1*, но код dynamic_cast -ing знает только это void*. Скажем, вы пытаетесь передать его в Derived2*, где оба производных класса имеют общую базу. Поверхностно, вы можете подумать, что все указатели указывают на тот же объект Base, который будет содержать указатель на соответствующую таблицу виртуальной диспетчеризации и RTTI, чтобы все могло висеть вместе. Но рассмотрим, что производные классы могут иметь несколько базовых классов, и поэтому необязательный подэкземпляр Base может быть не тем, к которому указывает Derived* - доступный только как void* -. Это не сработает. Вывод: компилятор должен знать эти типы, чтобы он мог выполнять некоторую настройку указателей на основе соответствующих типов.

Derived1* -----> [AnotherBase]
                 [[VDT]Base]    <-- but, need a pointer to start of
                 [extra members]    this sub-object for dynamic_cast

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

Ответ 3

Верно, что void* не может быть dynamically_cast ed из.

Вероятно, вы неправильно помните. С g++ 4.5 и следующий код

struct A {
    virtual ~A();
};

int main() {
    A a;
    void *p = &a;
    A* pa = dynamic_cast<A*>(p);
}

Я получаю следующую ошибку:

не может dynamic_cast 'p' (типа 'void *') набирать 'struct A *' (источник не является указателем на класс)

Ответ 4

Я думаю, вы путаете с dynamic_cast void*. Это является законным и получает указатель на наиболее производный объект класса.

dynamic_cast from void* является незаконным - тип, который должен быть издан, должен быть полиморфным - содержать хотя бы одну виртуальную функцию (счетчик виртуальных деструкторов тоже).

Ответ 5

Вы можете наложить указатель на полиморфный тип на void *, но не наоборот.