dynamic_cast от "void *" - PullRequest
       49

dynamic_cast от "void *"

35 голосов
/ 09 ноября 2010

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

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

Подскажите, пожалуйста, вопрос.

Ответы [ 5 ]

42 голосов
/ 09 ноября 2010

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
}
16 голосов
/ 09 ноября 2010

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

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

...

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

Таким образом, нет, значение (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* предположительно указывает на начало производного объекта, тогда как вам нужен указатель на подобъект базового класса, из которого происходит тип приведения.)

4 голосов
/ 09 ноября 2010

Это правда, что void* не может быть dynamically_cast изд.

Возможно, вы не помните.С 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 *'(источник не является указателем на класс)

1 голос
/ 09 ноября 2010

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

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

0 голосов
/ 09 ноября 2010

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

...