Введите приведение в стиле C :
Давайте рассмотрим следующую цитату:
Когда встречается выражение преобразования в стиле C, компилятор пытаетсяинтерпретировать его как следующие выражения приведения в следующем порядке: a) const_cast<new_type>(expression)
b) static_cast<new_type>(expression)
Если вы попытаетесь использовать reinterpret_cast
, , компиляция не удастся потому что reinterpret_cast
не является константным выражением, но static_cast
делает больше, чем просто приведение для системы типов. В этом случае static_cast
, скорее всего, указывает компилятору выполнить некоторое смещение, основанное на (известных во время компиляции) размерах Base1
, Base2
и Derived
, но static_cast может включать неявные преобразования,вызов конструктора new_type или вызов пользовательского оператора преобразования.
Кроме того, текст из static_cast
также гласит следующее:
2)Если new_type является указателем или ссылкой на некоторый класс D, а тип выражения является указателем или ссылкой на его не виртуальную базу B, static_cast выполняет downcast. Это понижение является неправильным, если B является неоднозначным, недоступным или виртуальным основанием (или основанием виртуального основания) из D.
9) Указатель на член некоторого класса D может быть повышен до указателячлену его однозначного, доступного базового класса B. Этот static_cast не проверяет, чтобы убедиться, что член действительно существует в типе времени выполнения указанного объекта.
Это на самом деле потому, что компоновка Derived
известен во всей своей полноте, и хотя этот макет технически определяется реализацией, компилятор точно знает этот макет, поскольку ни Base1
, ни Base2
не являются недоступными или виртуальными базами.
На самом деле мы видим случайгде это терпит неудачу, предоставляя недоступную базу:
class Base{};
class Base1 : public Base
{
int x;
};
class Base2 : public Base
{
int y;
};
class Derived
: public Base1
, public Base2
{
int z;
};
constexpr static Derived d{};
constexpr static const Derived* derived_ptr = &d;
constexpr static const Base1* base1_ptr = &d;
constexpr static const Base2* base2_ptr = &d;
// fail due to inaccessible base
static_assert(static_cast<const Derived*>(nullptr) == static_cast<const Base*>(nullptr), "err1" ); // fails
static_assert(static_cast<const Derived*>(derived_ptr) == static_cast<const Base*>(nullptr), "err2" ); // fails
// succeed
static_assert(static_cast<const Derived*>(derived_ptr) == static_cast<const Base1*>(base1_ptr), "err3" );
static_assert(static_cast<const Derived*>(derived_ptr) == static_cast<const Base2*>(base2_ptr), "err4" );
// and one of these as well???
static_assert(static_cast<const Base1*>(static_cast<const Derived*>(derived_ptr)) == base1_ptr, "err5" );
static_assert(static_cast<const Base2*>(static_cast<const Derived*>(derived_ptr)) == base2_ptr, "err6" );