Ответ 1
5.2.7 (ISO/IEC 14882, 12/29/2003) довольно четко сказано:
[о выражении
dynamic_cast<T>(v)
]Если
T
является "указателем на cv1B
" иv
имеет тип "указатель на cv2D
", так чтоB
является базовым классомD
, результатом является указатель на уникальный объектB
объектаD
, на который указываетv
. [... bla bla о cv1 и cv2...] и B должен быть доступным однозначным базовым классом of D (акцент мой)
(вспомните 11.2 "Базовый класс называется доступным, если доступный публичный член базового класса доступен".).
Это объясняет, почему работает первый бросок. Теперь, для второго:
[...]
В противном случае применяется проверка времени выполнения, чтобы увидеть, был ли объект указан или называемый
v
, может быть преобразован в тип, обозначенный или упомянутый наT
.Проверка выполнения выполняется логически следующим образом:
- Если в самом производном объекте, указанном (указанном) на
v
,v
точках (ссылается) на субъект базового классаpublic
объектаT
, и если только один объект типа T выводится из под-объекта, указанного (упомянутого) наv
, результатом будет указатель (ссылка на lvalue) на то, чтоT
объект.- В противном случае, если
v
указывает (ссылается) на под-объект базового классаpublic
самого производного объекта и тип самого производного объекта имеет базовый класс типаT
, который однозначен иpublic
, результатом является указатель (ссылка lvalue) на под-объектT
самый производный объект.- В противном случае проверка времени выполнения не выполняется.
Значение неудачного нажатия на тип указателя - это значение нулевого указателя требуемого типа результата. Неверный листинг для ссылочных типов бросков bad_cast (18.5.2).
Итак, похоже, что поведение, которое вы наблюдаете, связано с наследованием private
: даже если базовый класс доступен, он не является общедоступным, а стандарт требует публичного доступа, недоступного.
Раздражает, не так ли? У меня нет подходящего проекта С++ 0x, возможно, кто-то может отредактировать мой ответ с помощью кавычек из него, если все изменилось.
Есть ли другой способ добиться этого приведения?
Это зависит от того, что вы хотите сделать. В принципе, частное наследование - это еще одно устройство для выполнения композиции. Если вы действительно должны вернуть указатель на частный производный экземпляр, то либо сделайте наследование общедоступным, либо верните элемент.
В любом случае, вы с удовольствием узнаете, что static_cast
, похоже, не имеет этого ограничения:
5.2.9. [about
static_cast<T>(v)
] [...]Значение типа "указатель на cv1 B", где B - тип класса, может быть преобразовано в r-значение типа "указатель" to cv2 D ", где D - производный класс (раздел 10) из B, , если допустимое стандартное преобразование из" указателя на D "к" указателю на B" существует (4.10), cv2 - это та же самая cv-квалификация, что и более высокая cv-квалификация, чем cv1, и B не является виртуальным базовым классом D. Значение нулевого указателя (4.10) преобразуется в значение нулевого указателя тип назначения. Если rvalue типа "указатель на cv1 B" указывает на B, который на самом деле является под-объектом объект типа D, полученный указатель указывает на объект-объект типа D. В противном случае результат cast undefined.
поэтому, если вы точно знаете, что такое фактический динамический тип указателя, вам разрешено static_cast
внутри foo
.
Мне будет интересна любая дополнительная информация о , почему существует эта несогласованность.