Ответ 1
Преобразование Derived*
-to- Base*
, даже если наследование является приватным, разрешено в C-стиле и функциональных переводах. И нет, это не означает reinterpret_cast
в этом случае.
Это не допускается стандартом, но он почти выглядит так, как будто это разрешено, поэтому это тонкая ошибка.
5.2.3 Явное преобразование типа (функциональная нотация) [expr.type.conv]
1 [...] Если список выражений является единственным выражением, выражение преобразования типа эквивалентно (в определении и, если определено по смыслу), соответствующему выражению (5.4). [...]
5.4 Явное преобразование типов (литая нотация) [expr.cast]
4 Конверсии, выполняемые
- a
const_cast
(5.2.11),- a
static_cast
(5.2.9),- a
static_cast
, за которым следуетconst_cast
,- a
reinterpret_cast
(5.2.10) или- a
reinterpret_cast
, за которым следуетconst_cast
,может выполняться с использованием буквенного обозначения преобразования явного типа. Используются те же смысловые ограничения и поведение, за исключением того, что при выполнении
static_cast
в следующих ситуациях преобразование действительно, даже если базовый класс недоступен:
- указатель на объект типа производного класса или lvalue или rvalue типа производного класса может быть явно преобразуется в указатель или ссылается на однозначный тип базового класса, соответственно;
- [...]
В сложившейся ситуации компилятор интерпретирует его как static_cast
от Derived*
до auto_ptr<Base>
, а в этом static_cast
указатель на объект производного типа класса преобразуется в указатель однозначного типа базового класса. Таким образом, похоже, что стандарт позволяет это.
Однако преобразование из Derived*
в Base*
неявно, оно просто выполняется как часть явного другого преобразования. Поэтому, в конце концов, нет, стандарт действительно этого не позволяет.
Вы можете сообщить об этом как об ошибке. Из комментария Csq мы узнаем, что существует связанный отчет, в котором явный static_cast
также позволяет это преобразование, но это не совсем то же самое. В этом случае преобразование из Derived*
в Base*
является явным, но оно здесь неявно, и Visual С++ обычно отклоняет это в неявных преобразованиях.
Обратите внимание, что в функциональных методах, которые используют несколько выражений, эта неверная интерпретация невозможна: компилятор правильно отклоняет следующее:
class Base { };
class Derived : Base { };
template <typename T>
class Ptr {
public:
Ptr(T *a, T *b) { }
};
int main() {
Ptr<Base>(new Derived, new Derived);
// error C2243: 'type cast' : conversion from 'Derived *' to 'Base *' exists, but is inaccessible
}