Я, конечно, надеюсь, что это то, что вы делаете в качестве академического c упражнения. Пожалуйста, никогда не пишите никакого реального кода, который бы хоть как-то напоминал это. Я не могу указать на все проблемы с этим фрагментом кода, поскольку здесь есть проблемы практически со всем.
Однако, чтобы ответить на реальный вопрос - это совершенно неопределенное поведение. В C ++ 17 это раздел 8.2.10 [expr.reinterpret.cast]. Используйте фразу в скобках, чтобы получить соответствующий раздел для предыдущих стандартов.
РЕДАКТИРОВАТЬ Я думал, что краткого ответа будет достаточно, но запрашивались дополнительные детали. Я не буду упоминать другие проблемы с кодом, потому что они просто запутают воду.
Здесь есть несколько ключевых проблем. Давайте сосредоточимся на reinterpret_cast.
Child ch;
Wrapper<Child> &wr = reinterpret_cast<Wrapper<Child>&/**/>(ch);
Большая часть формулировки в spe c использует указатели, поэтому, основываясь на 8.2.10 / 11, мы немного изменим пример кода на этот.
Child ch;
Wrapper<Child> *wr = reinterpret_cast<Wrapper<Child>*>(&ch);
Здесь приведена часть стандарта для этого обоснования в кавычках.
Выражение glvalue типа T1 может быть приведено к типу «ссылка на T2», если выражение типа « указатель на T1 »может быть явно преобразован в тип« указатель на T2 »с помощью reinterpret_cast. Результат ссылается на тот же объект, что и источник glvalue, но с указанным типом. [Примечание: то есть для l-значений эталонное приведение reinterpret_cast (x) имеет тот же эффект, что и преобразование * reinterpret_cast (& x) со встроенными операторами & и * (и аналогично для reinterpret_cast (x)). - примечание конца] Временное создание не производится, копирование не производится, а конструкторы (15.1) или функции преобразования (15.3) не вызываются.
Одна тонкая маленькая часть стандарта - 6.9.2 / 4, который позволяет в некоторых особых случаях обрабатывать указатель на один объект, как если бы он указывал на объект другого типа.
Два объекта a и b являются взаимозаменяемыми по указателю, если:
(4.1) - это один и тот же объект, или
(4.2) - один является объектом объединения стандартной компоновки, а другой является нестационарным c членом данных этого объекта (12.3 ) или
(4.3) - один из них является объектом класса стандартной компоновки, а другой - первым не-статическим c членом данных этого объекта, или, если у объекта нет нестатического c члены данных, первый подобъект базового класса этого объекта (12.2) или
(4.4) - существует объект c такой, что a и c являются взаимозаменяемыми по указателю, а c и b преобразуются указателем.
Если два o bject являются взаимозаменяемыми по указателю, тогда они имеют одинаковый адрес, и можно получить указатель на один из указателя на другой через reinterpret_cast (8.2.10). [Примечание: объект массива и его первый элемент не являются взаимозаменяемыми по указателю, даже если они имеют один и тот же адрес. - конец примечания]
Однако ваш случай не соответствует этому критерию, поэтому мы не можем использовать это исключение для обработки указателя на Child
, как если бы он был указателем на Wrapper<Child>
.
Мы будем игнорировать материал о reinterpret_cast, который не имеет отношения к приведению между двумя типами указателей, поскольку этот случай касается только типов указателей.
Обратите внимание на последнее предложение 8.2.10 / 1
Преобразования, которые могут быть выполнены явно с использованием reinterpret_cast, перечислены ниже. Никакое другое преобразование не может быть выполнено явно с использованием reinterpret_cast.
Ниже приведены 10 абзацев.
В параграфе 2 говорится, что reinterpret_cast не может отбрасывать константу. Не наша забота.
В параграфе 3 говорится, что результат может давать или не давать другое представление.
Параграфы 4 и 5 касаются преобразования между указателями и целочисленными типами.
Пункт 6 посвящен приведению указателей на функции.
Пункт 8 посвящен преобразованию указателей функций и указателей объектов.
Пункт 9 касается преобразования значений нулевых указателей.
Параграф 10 посвящён конвертации между указателями на элементы.
Параграф 11 цитируется выше и в основном говорит, что приведение ссылок похоже на приведение указателей.
Таким образом, остается параграф 7, в котором говорится. 1068 *
Указатель объекта может быть явно преобразован в указатель объекта другого типа. 73 Когда значение v типа указателя объекта преобразуется в тип указателя объекта «указатель на cv T», результатом является static_cast (static_cast (v)). [Примечание: преобразование значения типа «указатель на T1» в тип «указатель на T2» (где T1 и T2 являются типами объектов, а требования к выравниванию для T2 не более строгие, чем требования для T1) и обратно к его исходному типу возвращает исходное значение указателя - конец примечания]
Это означает, что мы можем переходить туда и обратно между этими двумя типами указателей в течение всего дня. Тем не менее, это все, что мы можем сделать безопасно. Вы делаете больше, и да, есть несколько исключений, которые допускают некоторые другие вещи.
Здесь 6.10 / 8
Если программа пытается получить доступ к сохраненному значение объекта через glvalue, отличное от одного из следующих типов, поведение не определено:
(8.1) - тип объекта Dynami c,
(8.2) - cv-квалифицированная версия типа объекта Dynami c,
(8.3) - тип, подобный (как определено в 7.5) типу объекта Dynami c,
(8.4) - тип, который является типом со знаком или без знака, соответствующим типу динамического c объекта,
(8.5) - тип, который является типом со знаком или без знака, соответствующим cv версия объекта типа Dynami c,
(8.6) - агрегатный или объединенный тип, включающий в себя один из вышеупомянутых типов среди своих элементов или нестатических c членов данных (включая , рекурсивно, элемент или не стати c член данных субагрегата или объединенного объединения),
(8.7) - тип, который является (возможно, cv-квалифицированным) типом базового класса типа Dynami c объекта,
(8.8) - тип char, unsigned char или std :: byte.
Ваш случай не удовлетворяет ни одному из них.
В вашем случае вы принимаете указатель на один тип и заставляющий компилятор делать вид, что он указывает на другой тип. Неважно, как эти два взгляда выглядят - знаете ли вы, что полностью стандартному компилятору, который соответствует требованиям, не нужно помещать данные для производного класса после данных для базового класса? Эти детали НЕ являются частью стандарта C ++, но являются частью ABI, которую реализует ваш компилятор.
На самом деле, очень мало случаев, когда использование reinterpret_cast для чего-либо другого, кроме переноса указателя и последующего приведения его обратно к его оригинальный тип, который не вызывает неопределенного поведения.