Почему этот static_cast не разрешен?

У меня есть объект класса A, который я хочу разместить в пользовательском объекте стека. Для этого я просто перемещаю указатель стека на столько байтов, сколько имеет размер объекта, и возвращаю его предыдущее значение:

class A : public B {}; //B is from a precompiled library

class stack {
public:
    stack(void): _top(&_storage[0]) {}

    template <typename T>
    inline T* push(void) {
        T* ptr = static_cast<T*>(_top);

        _top += sizeof(T);

        return ptr;
    }

    //...

private:
    char _storage[1024];
    char* _top;
};

stack _stack;

int main(int argc, char** argv) {
    A* a = _stack.push<A>(); //ignore the lack of a constructor call

    return 0;
}

Visual C++ просто говорит мне, что static_cast не может преобразовать char* в A*. Обычное приведение в стиле C не дает мне этой ошибки, но я бы предпочел быть более явным и избегать динамического приведения (A наследует от другого класса, но не вносит вклад в vtable, которого у него нет). Есть ли разница между ними в этом случае?


person NmdMystery    schedule 15.01.2014    source источник


Ответы (3)


По дизайну.

Преобразование static_cast не предназначено для преобразования между несвязанными типами указателей, для этого вам нужно использовать reinterpret_cast. Если вы хотите четко указать актерский состав, который вы делаете, используйте правильный. Приведение стиля C в этом случае сделает reinterpret_cast.

Вам действительно нужно исследовать различные операторы приведения, так как комментарий к dynamic_cast также не имеет особого смысла.

person David Rodríguez - dribeas    schedule 15.01.2014
comment
Я думал, что понял, что dynamic_cast меняет динамический тип объекта, это не так? - person NmdMystery; 15.01.2014
comment
@NmdMystery: Ничто не меняет динамический тип объекта. Объект имеет тип, когда он создается, и этот тип никогда не меняется (ссылки или указатели могут иметь другой тип, как в базе, но объект всегда одного и того же типа). Опять же, лучшее, что вы можете сделать, это найти книгу или учебник и развеять свои сомнения. - person David Rodríguez - dribeas; 15.01.2014
comment
Что ж, это была честная ошибка, я думал, что у меня уже есть довольно хорошее представление о том, что делает каждый актерский состав. Думаю нет. - person NmdMystery; 15.01.2014
comment
@NmdMystery: Не беспокойтесь. Если бы это было сочтено чем-то другим, кроме честной ошибки, вероятно, было бы несколько голосов, чтобы закрыть. - person David Rodríguez - dribeas; 16.01.2014

Как уже говорили другие, решение состоит в том, чтобы использовать reinterpret_cast, который предназначен для использования при приведении между несвязанными типами указателей:

T* ptr = reinterpret_cast<T*>(_top);

Если вместо этого вы используете placement new, вы не только избегаете проблемы приведения типов, но также решаете проблему отсутствия вызова конструктора для типов, у которых есть конструктор:

T* ptr = new(_top) T();
person Remy Lebeau    schedule 15.01.2014

Нет явного или неявного преобразования char* в A*. Вы хотите, чтобы reinterpret_cast‹> выполнял этот тип приведения.

Подробнее см. Этот ответ SO

person sbaker    schedule 15.01.2014