2015-09-10 7 views
3

Этот вопрос о том, какой C++ style cast должен использоваться, чтобы произвести это преобразование. Я знаю, что приведение стиля C может достичь этого.Какой тип ролей должен идти от родителя к ребенку?

Для следующей class структуры:

class Foo {}; 

class Bar : public Foo {}; 

Скажи, что я даюсь: Foo* ptr; и я хочу, чтобы привести его к Bar*, который я должен использовать тип броска? Похоже, я должен использовать dynamic_cast как это:

Используется для превращения полиморфных типов

Я хотел избежать dynamic_cast, так как это время выполнения броска.

+0

Это то, чего вам следует избегать, делая такие вещи, является признаком проблем дизайна. Если вы считаете, что вам действительно нужно это, вы можете сравнить типы типов классов, и если это соответствует, вы можете static_cast указатель ...это быстрее, чем dynamic_cast, но не будет работать, если вы не знаете точный целевой класс. – Melkon

+0

@Melkon, как проверять typeid быстрее, чем dynamic_cast? Какой компилятор и настройки вы видели? –

+1

@MarkRansom: проверка типа не пересекает иерархию классов. – Melkon

ответ

6

Вы верны, что dynamic_cast, как правило, наиболее подходит для этой ситуации. Однако, если вы знаете, что указатель фактически указывает на объект производного класса, вы можете использовать static_cast для преобразования. Если вы ошибаетесь, а указатель не производного класса, вы получите неопределенное поведение.

+0

Я действительно знаю, что 'ptr' is-a' Bar * '. Поэтому я предполагаю, что вы ссылаетесь на 2-й тип преобразования в этом списке: http://en.cppreference.com/w/cpp/language/static_cast#Explanation –

+0

@JonathanMee да, вот что я говорю - хотя я не считаю необходимым, чтобы базовый класс был не виртуальным. –

+0

Вы осмеливаетесь бросить вызов мудрости http://en.cppreference.com O.O –

1

static_cast будет работать нормально, если вы уверены, что объект, который вы бросаете, действительно является тем типом, который вы ожидаете от него. Основываясь на примере, который вы дали, похоже, что вы уверены.

1

Для ясности:

Я хотел избежать dynamic_cast, так как это время выполнения броска.

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

Если вы думали, что ваш объект действительно был в Bar, но ошибались, dynamic_cast<Bar*> даст вам nullptr или dynamic_cast<Bar&> сгенерирует исключение. В любом случае у вас есть возможность справиться со своей ошибкой во время выполнения во время выполнения. Как указывал M.M, это доступно только в том случае, если ваш базовый класс имеет или наследует хотя бы один виртуальный метод.

Теперь, если, случайно, вы можете быть статический определенными динамическим типом вашего объекта действительно являетсяBar, вы можете использовать static_cast. Однако, если вы ошибаетесь, у вас есть Undefined Behavior и нет возможности обнаружить или обработать ошибку.

например.

struct Foo { virtual ~Foo(){} }; 
struct Bar : public Foo {}; 

// safe, may return nullptr 
Bar* safe_ptr_cast(Foo *f) { return dynamic_cast<Bar*>(f); } 

// safe, may throw but you can catch it 
Bar& safe_ref_cast(Foo &f) { return dynamic_cast<Bar&>(f); } 

// unsafe - if you're wrong, you just broke everything 
Bar* unsafe_ptr_cast(Foo *f) { return static_cast<Bar*>(f); } 

Кстати, если ваша проблема с временем запуска броском производительность, рискуя UB, чтобы сэкономить условное время, прежде чем у вас есть код для профилирования является определением преждевременной оптимизации.

+1

Ваш код неверен, так как 'dynamic_cast' может использоваться только для классов, имеющих хотя бы одну виртуальную функцию. –

+0

«статический тип вашего объекта базового класса действительно является баром» - это не то, что означает * статический тип *. –

+0

Хорошая точка, это неудачная фраза. – Useless

Смежные вопросы