2016-07-13 4 views
2

Я проходил через «Multiple Inheritance for C++ by Bjarne Stroustrup, Published in the May 1999 issue of "The C/C++ Users Journal"». Ниже отрывок из того же (Страница 5/17),Когда и как принято решение использовать бросок или нет?

4,4 Casting

Явные и неявные литье также может включать в себя изменение значения указателя с дельта:

class A { void f(); }; 
class B { int f(); }; 
class C : A, B { }; 

C* pc; 
B* pb; 
pb = (B*)pc; // pb = (B*)((char*)pc+delta(B)) 
pb = pc; // pb = (B*)((char*)pc+delta(B)) 
pc = pb; // error: cast needed <-------------------- HERE 
pc = (C*)pb; // pc = (C*)((char*)pb-delta(B)) 

Он показывает нам, что pb = pc можно сделать, не произнося его явно. Это определенно означает, что литье обрабатывается неявно. Затем

  1. Почему, когда мы пытаемся установить pc = pb указатель, нужно лить?
  2. Что и где это правило, которое направляет это?
  3. Связано ли это с приращением/декрементом указателя по значению дельта?

EDIT

Jonathan Mee отметили этот вопрос как дубликат "What Type of Cast to Go from Parent to Child?". Боюсь, я не согласен. Мой вопрос касается, Почему литье и где это правило, которое направляет нас на литье или не на литье. Я думаю, что логика может быть такой же, но концепция совершенно другая. В его вопросе он сомневается (настаивает на том, чтобы не использовать динамический кастинг) использование dynamic_cast и static_cast. Мое сомнение по-прежнему остается за ним.

+0

Вы будете иметь хорошее объяснение здесь: http://stackoverflow.com/questions/25137705/c-memory-layout-of-classes-using-inheritance – Dfaure

+0

Возможный дубликат [Какой тип Cast Пойти от родителя к ребенку?] (http://stackoverflow.com/questions/32506579/what-type-of-cast-to-go-from-parent-to-child) –

+0

@JonathanMee - Мой вопрос касается, почему кастинг и где это правило, которое побуждает нас бросать или не бросать. Я думаю, что логика может быть такой же, но концепция совершенно другая. Мое сомнение против вашего сомнения не имеет никакого сходства, которое должно быть отмечено как дубликат. В вашем вопросе вы знаете, почему вы бросаете, но у вас есть сомнения относительно того, какой из них использовать. Я сомневаюсь, что все еще несколько шагов за твоим :) – Abhineet

ответ

3

Это связано с типами знает, что объекты имеют. Каждый C также является B, поэтому преобразование всегда работает (неявно).

Каждый B не является частью C, поэтому вам необходимо сообщить компилятору, что вы точно знаете, что это конкретное преобразование будет работать.Это использование явного приведения.

+0

Возможно, это выходит за рамки, но каково поведение, когда подобный прилив (parent -> child) недопустим? – rtmh

+0

Сладкий и простой. Мне понравилась часть ответа. И это определенно очищает много воздуха вокруг неявного и явного приведения. – Abhineet

1

Ну, компилятор знает, что указатель на C можно ссылаться как унаследованная class A или B - так литье до к A или B может быть сделано неявно. Иными словами, компилятор не знает, что указатель относится к объекту C. Это может быть другой класс, который также наследует A. Добавляя приведение, вы по существу говорите: «не беспокойтесь компилятора - я знаю, что это на самом деле класс типа C».

+0

'so ** отбрасывание ** на A или B может быть сделано неявно. Я не думаю, вы имеете в виду понижение. Спасибо за ответ. – Abhineet

+1

кричит. Хороший улов. Изменено, – noelicus

1

В вашем случае это довольно просто. Вы пытаетесь назначить указатель на объект класса B указателю, который указывает на объекты класса C.

По сути, вы не можете этого сделать, потому что объекты класса C также обеспечивают функциональность класса A, объекты которого класса B этого не делают. Таким образом, использование объекта класса B, где ожидается объект C, не определено, потому что B не может предоставить все, что C имеет.

2

The rules на допустимых неявных преобразований для неосновных видов являются следующие:

  • Нулевые указатели могут быть преобразованы в указатели любого типа
  • Указатели любого типа могут быть преобразованы в недействительных указателей.
  • Указатель upcast: указатели на производный класс могут быть преобразованы в указатель доступного и однозначного базового класса без изменения его квалификации или volatile.

Так что, когда от приведения к базовому типу в C* к B* явное приведение не является необходимым. Но так как литье из B* к C* является указателем опущенных С-Стиль литой может быть использован, но одно из следующих действий является предпочтительным:

  • dynamic_cast может быть использовано при условии, что выражение является B* и new_type это C* будет выполнена эта проверка времени выполнения и смиренный должны быть разрешен :
  1. в анализируется наиболее производный объект, обозначенный/идентифицированный выражением. Если в этом объекте точки выражения/ссылаются на общедоступную базу Derived, и если из подобъекта, указанного/идентифицированного выражением, выведен только один подобъект производного типа, то результат литых точек/относится к этому производному подобъекту. (Это называется «downcast».)
  2. В противном случае, если точки выражения/ссылаются на общедоступную базу самого производного объекта, и, одновременно, наиболее производный объект имеет однозначный публичный базовый класс типа Derived, результат литых точек/относится к этому производному (это известно как «sidecast».)
  3. В противном случае проверка времени выполнения не выполняется. Если dynamic_cast используется для указателей, возвращается значение null-указателя типа new_type.
  • reinterpret_cast могут быть использованы, и всегда будет успешным.Но использование это результат определяется только, если для B является AliasedType и C является DynamicType, один из этих условий будет выполнено, 2 й пуля позволяет подавленным:
  • AliasedType является (возможно, резюме квалифицированное) DynamicType
  • AliasedType и DynamicType оба (возможно, многоуровневые, возможно, резюме квалифицированного на каждом уровне) указатели на тот же тип Т
  • AliasedType является (подписаны, возможно, резюме квалифицированного) или без знака варианта DynamicType
  • AliasedType - это совокупный тип или тип объединения, который содержит один из вышеупомянутых типов как элемент или нестатический член (включая рекурсивно, элементы субагрегатов и нестатические элементы данных объединенных объединений): это делает его чтобы получить полезный указатель на структуру или объединение, заданный указателем на его нестатический элемент или элемент.
  • AliasedType является (возможно, резюме квалифицированных) базовый класс DynamicType
  • AliasedType является char или unsigned char: это позволяет экспертизу объекта представления любого объекта как массив беззнаковых символов.
  • static_cast также может быть использован, если и только если оно известно , что B* фактически полиморфно адресации C объекта. Если это не так, и будет предпринята попытка static_cast, это приведет к неопределенному поведению.