Является ли приведение базового указателя к производному указателю опасным в любом случае? - PullRequest
3 голосов
/ 26 августа 2011

Я всегда избегал приведений в C ++ (static_cast, const_cast, dynamic_cast [я также избегаю RTTI] и т. Д.), Потому что я считаю их пустой тратой текста и никогда не видел никаких преимуществ, поэтому я используюПреобразование в стиле C исключительно.

Мой вопрос: если у вас есть иерархия наследования и указатель на базовый тип, можете ли вы безопасно привести базовый указатель к производному указателю с приведением в стиле C (при условии, чтопочему-то вы абсолютно уверены, что базовый указатель указывает на экземпляр производного типа) без каких-либо событий, происходящих за кулисами, которые вызовут, казалось бы, необъяснимые сбои?

Я спрашиваю об этом, потому что прочитал в одном из комментариев другой вопросчто использование приведения в стиле C из базового к производному типу не будет «корректировать указатель» или что-то в этом роде.Я постараюсь найти точный комментарий снова.

Ответы [ 5 ]

7 голосов
/ 26 августа 2011

Использование static_cast или dynamic_cast для приведения гарантирует некоторую безопасность.
static_cast выдает ошибку времени компиляции, если приведение недопустимо, в то время как
dynamic_cast вызывает исключение для ссылок иливозвращает нулевой указатель в случае неправильного приведения во время выполнения.

Таким образом, они лучше, чем броски в стиле C, в основном благодаря безопасности, которую они обеспечивают.

Если вы абсолютно уверены, что приведение является действительным, даже приведение в стиле c просто делает то же самое, но лучше использовать язык, обеспеченный безопасностью, а не управлять им самостоятельно (поскольку нам не нужно).

1 голос
/ 26 августа 2011

Приведения в стиле C ++ важны в коде шаблона. В коде шаблона гораздо меньше уверенности в типах объектов, из которых вы преобразуете данные, в которые они были добавлены пользователем. Приведение в стиле C ++ выдаст вам ошибки компилятора, если вы в конечном итоге выполните нежелательное приведение (например, статическое приведение между несвязанными типами указателей), но приведение в стиле C все равно выполнит приведение.

Например (тривиальный пример)

template <class T>
T* safe_downcast(Base* ptr)
{
  return static_cast<T*>(ptr);
}

В этой функции не было бы ничего безопасного, если бы я использовал приведение в стиле C.

Но я согласен, за пределами кода шаблона я часто использую приведение в стиле C.

1 голос
/ 26 августа 2011

Если ваш производный класс вводит дополнительные члены, да, я думаю, что все может пойти не так, если вы попытаетесь индексировать указатель или индексировать указатель как массив.

Обратите внимание на следующее:

class base
{
public:
    int _data1;

    base () : _data1(0) {}
};

class derived : public base
{
public:
    int _data2;

    derived () : _data2(1) {}
};

int main ()
{
    base *_base_ptr = new derived[10];

    // this isn't going to work correctly, because the compiler will use `sizeof(base)` 
    // to do the pointer offsets, rather than sizeof(derived)...
    int _data = _base_ptr[1]._data1;

    delete[] _base_ptr;

    return _data;
}

Запуск этого фрагмента в ideone возвращает 1 вместо ожидаемого 0.

Надеюсь, это поможет.

1 голос
/ 26 августа 2011

A dynamic_cast на указатель (не на ссылку) дает вам возможность обнаружить ошибку и обработать ее;простой C бросок не будет.Но, если вы абсолютно уверены в типах, приведение в стиле C - хотя и отвратительное - должно работать нормально;это было то, что должно было работать до того, как появился стандарт C ++.

0 голосов
/ 26 августа 2011

Если вы абсолютно уверены, что указатель базового класса действительно указывает на экземпляр производного типа, почему у вас вообще есть базовый указатель? Также: Звучит так, как будто это классический случай для виртуальных функций. Если по какой-то причине вы хотите избежать виртуальных вызовов (производительность, ...), поищите CRTP.

Я использую приведение в стиле C ++ главным образом потому, что они напоминают мне, чтобы проверить, является ли приведение абсолютно необходимым или нет, выглядя уродливо. Я стараюсь избегать reinterpret_cast и dynamic_cast, если это вообще возможно (в большинстве случаев), и я использую static_cast в основном внутри шаблонных классов CRTP, где все в порядке.

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