класс — Когда в C ++ запрещена трансляция?

Я почти уверен, что понимаю общую разницу между апскейтингом и спукованием, особенно в C ++. Я понимаю, что мы не можем всегда снижать рейтинг, потому что приведение указателя базового класса к указателю производного класса предполагает, что объект базового класса, на который указывает указатель, имеет все члены производного класса.

В начале семестра мой профессор сказал классу, что иногда выгонять в C ++ также незаконно, но я, кажется, упустил причину в своих заметках, и я не могу вспомнить, когда это произошло.

Когда это незаконно, чтобы выгнать в C ++?

56

Решение

Если под «нелегальным» вы подразумеваете плохо сформированного, то это недопустимо, если базовый класс недоступен или неоднозначен.

  • Он недоступен, когда, например, базовый класс является закрытым.

    class A {};
    class B : A {};
    ...
    B b;
    A *pa = &b; // ERROR: base class is inaccessible
    

    Обратите внимание, что даже в C ++ 11 приведение в стиле C может «пробить» защиту доступа и выполнить формально корректное преобразование.

    A *pa = (A *) &b; // OK, not a `reinterpret_cast`, but a valid upcast
    

    Этого использования следует избегать, конечно.

  • Это неоднозначно, если ваш тип источника содержит несколько базовых подобъектов целевого типа (через множественное наследование).

    class A {};
    class B : public A {};
    class C : public A {};
    class D : public B, public C {};
    
    D d;
    A *pa = &d; // ERROR: base class is ambiguous
    

    В таких случаях выгрузка может быть выполнена путем явного «перехода» по желаемому пути выведения с промежуточными подъёмами к точке, где база больше не является двусмысленной.

    B* pb = &d;
    A* pa = pb; // OK: points to 'D::B::A' subobject
    
48

Другие решения

Если базовый класс неоднозначен (наследуется два или более раз по разным путям), то вы не сможете выполнить upcast за один шаг.

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


Standardese.

C ++ 11 §5.4 / 4:

» … В актерском составе static_cast в следующих ситуациях преобразование
допустимо, даже если базовый класс недоступен:

  • указатель на объект производного типа класса или lvalue или rvalue производного типа класса может быть явно
    преобразуется в указатель или ссылку на однозначный тип базового класса соответственно;
  • указатель на член производного типа класса может быть явно преобразован в указатель на член
    однозначный не виртуальный тип базового класса;
  • указатель на объект однозначного не виртуального типа базового класса, glvalue однозначного
    не виртуальный тип базового класса или указатель на член однозначного не виртуального типа базового класса может быть явно преобразован в указатель, ссылку или указатель на член производного типа класса,
    соответственно.

Пример двусмысленности:

struct Base {};
struct M1: Base {};
struct M2: Base {};
struct Derived: M1, M2 {};

auto main() -> int
{
Derived d;
//static_cast<Base&>( d );                      //! Ambiguous
static_cast<Base&>( static_cast<M2&>( d ) );    // OK
}

Пример недоступной базы с (обычно) корректировкой адреса в приведении:

struct Base { int value; Base( int x ): value( x ) {} };

class Derived
: private Base
{
public:
virtual ~Derived() {}       // Just to involve an address adjustment.
Derived(): Base( 42 ) {}
};

#include <iostream>
using namespace std;

auto main() -> int
{
Derived d;
Base& b = (Base&) d;
cout << "Derived at " << &d << ", base at " << &b << endl;
cout << b.value << endl;
};
17

Есть два случая, когда апкастинг плохо сформирован в C ++ (диагностируется во время компиляции):

  1. Рассматриваемый базовый класс не доступный:

    class base {};
    class derived : base {};
    
    int main() {
    derived x;
    base& y = x; // invalid because not accessible.
    // Solution: C-style cast (as static_cast without access-check)
    base& y1 = (base&)x;
    }
    
  2. Подобъект базового класса, о котором идет речь, не однозначный:

    class base {};
    struct A1 : base {};
    struct A2 : base {};
    
    struct derived : A1, A2 {};
    int main() {
    derived x;
    base& y = x; // invalid because ambiguous.
    // Solution 1, scope resolution:
    base& y1 = static_cast<A1::base&>(x);
    base& y2 = static_cast<A2::base&>(x);
    // Solution 2, intermediate unambiguous steps:
    A1& a1 = x;
    A2& a2 = x;
    base& ya1 = a1;
    base& ya2 = a2;
    }
    
10
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector