Когда и как принимается решение об использовании гипса или нет?

Я просматривал множественное наследование для C++ Бьерн Страуструп, опубликовано в майском выпуске журнала C/C++ Users Journal за 1999 г.. Приведенный ниже отрывок взят из того же (Страница 5/17),

4.4 Кастинг

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

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. Связано ли это с увеличением/уменьшением указателя по дельта-значению?

ИЗМЕНИТЬ

Джонатан Ми отметил этот вопрос как дубликат Какой тип приведения перейти от родительского к дочернему?. Боюсь, я не согласен. Мой вопрос касается почему выполняется кастинг и где находится это правило, которое предписывает нам кастовать или не кастовать. Я думаю, что логика может быть той же, но концепция совершенно другая. В своем вопросе он сомневается (настаивает на том, чтобы не использовать динамическое приведение) в использовании dynamic_cast и static_cast. Мое сомнение все еще на несколько шагов позади его.


person Abhineet    schedule 13.07.2016    source источник
comment
Здесь у вас будет хорошее объяснение: stackoverflow.com/questions/25137705/   -  person Dfaure    schedule 13.07.2016
comment
Возможный дубликат Какой тип приведения перейти от родительского к Ребенок?   -  person Jonathan Mee    schedule 13.07.2016
comment
@JonathanMee - Мой вопрос о том, почему кастинг и где находится это правило, которое предписывает нам кастовать или не кастовать. Я думаю, что логика может быть той же, но концепция совершенно другая. Мое сомнение против вашего сомнения не имеет никакого сходства, чтобы быть помеченным как дубликат. В своем вопросе вы знаете, почему вы используете кастинг, но у вас есть сомнения относительно того, какой из них использовать. Мои сомнения все еще на несколько шагов позади ваших :)   -  person Abhineet    schedule 13.07.2016


Ответы (4)


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

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

person Bo Persson    schedule 13.07.2016
comment
Возможно, это выходит за рамки, но каково поведение, когда такое приведение (родитель -> ребенок) недействительно? - person rtmh; 13.07.2016
comment
Мило и просто. Мне понравилась часть ответа. И это определенно проясняет ситуацию вокруг имплицитного и явного актерского состава. - person Abhineet; 14.07.2016

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

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

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

  • dynamic_cast можно использовать, если выражение — B*, а new_type — C* эта проверка во время выполнения будет выполнена, и приведение вниз должно быть разрешено 1:
  1. Проверяется наиболее производный объект, указанный/идентифицированный выражением. Если в этом объекте выражение указывает/ссылается на общедоступную базу Derived, и если только один подобъект типа Derived является производным от подобъекта, на который указывает/идентифицируется выражением, то результат приведения указывает/ссылается на этот подобъект Derived. (Это известно как «подавленный».)
  2. В противном случае, если выражение указывает/ссылается на общедоступную базу самого производного объекта, и одновременно самый производный объект имеет однозначный общедоступный базовый класс типа Derived, результат приведения указывает/ссылается на этот производный (это известно) как "побочный эффект".)
  3. В противном случае проверка среды выполнения завершится неудачно. Если для указателей используется dynamic_cast, возвращается нулевое значение указателя типа new_type.
  • Можно использовать reinterpret_cast, и он всегда будет успешным. Но использование его результата определено только в том случае, если B является AliasedType, а C является DynamicType, выполняется одно из этих условий, 2nd маркер допускает приведение вниз:
  • AliasedType - это (возможно, cv-квалифицированный) DynamicType
  • AliasedType и DynamicType являются (возможно, многоуровневыми, возможно, cv-квалифицированными на каждом уровне) указателями на один и тот же тип T.
  • AliasedType — это (возможно, cv-квалифицированный) подписанный или неподписанный вариант DynamicType.
  • AliasedType — это агрегатный тип или тип объединения, который содержит один из вышеупомянутых типов в качестве элемента или нестатического члена (включая, рекурсивно, элементы подагрегатов и нестатические элементы данных содержащихся объединений): это делает безопасным получение полезный указатель на структуру или объединение с указателем на его нестатический член или элемент.
  • AliasedType — это (возможно, cv-квалифицированный) базовый класс DynamicType.
  • AliasedType имеет значение char или unsigned char: это позволяет исследовать объектное представление любого объекта в виде массива символов без знака.
  • static_cast также можно использовать тогда и только тогда, когда известно, что B* на самом деле полиморфно адресует объект C. Если это не так и будет предпринята попытка static_cast, результатом будет неопределенное поведение.
person Jonathan Mee    schedule 13.07.2016

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

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

person Jonas Schäfer    schedule 13.07.2016

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

person noelicus    schedule 13.07.2016
comment
so **casting down** to A or B can be done implicitly Я не думаю, что вы имеете в виду унижение. Но спасибо за ответ. - person Abhineet; 14.07.2016
comment
упс Хороший улов. Изменено, - person noelicus; 14.07.2016