Даункинг в упс - PullRequest
       36

Даункинг в упс

0 голосов
/ 08 сентября 2018
class Parent
{};
class A_child : public Parent
{
  void A_method();
};
class B_child : public Parent
{
  void B_method();
};
void main()
{
  A_child a;
  Parent *p = &a;
  B_child *b = (B_child*)&p;
  b->B_method();
}

Этот кусок кода находится на C ++. Это логическая ошибка, так как мы пытаемся превратить «кошку» в «собаку». Но это работает. Кто-нибудь может объяснить, почему и как?

Ответы [ 2 ]

0 голосов
/ 08 сентября 2018

Может кто-нибудь объяснить, почему и как?

Parent - это основа B_child, и поэтому преобразование из типа Parent *p в B_child* правильно сформировано.Однако поведение доступа к указанному объекту через этот преобразованный указатель определяется только в том случае, если p действительно указывает на базовый подобъект экземпляра B_child.

Предварительное условие не выполняется, и поэтомуПоведение программы не определено.Возможны следующие варианты поведения, ни одно из которых не гарантировано:

 - working
 - not working
 - random output
 - non-random output
 - the expected output
 - unexpected output
 - no output
 - any output
 - crashing at random
 - crashing always
 - not crashing at all
 - corruption of data
 - different behaviour, when executed on another system
 -                    , when compiled with another compiler
 -                    , on tuesday
 -                    , only when you are not looking
 - same behaviour in any or all of the above cases
 - anything else within the power of the computer (hopefully limited by the OS)

Никогда static_cast, reinterpret_cast или стиль C не приводят выражение к другому типу, если you не может доказатьчто актерский состав правильный.Вы можете использовать dynamic_cast в случае, если вы не уверены.

0 голосов
/ 08 сентября 2018

Это вероятно, но не гарантировано , чтобы не вызвать ошибку, потому что ваш B_method эффективно static.

  1. Метод может быть найден и вызван без разыменования указателя класса
  2. Самому методу не нужно разыменовывать указатель класса.

Как только метод становится virtual (и теперь для доступа к виртуальной таблице требуется указатель класса для поиска адреса функции), доступа к данным класса, или вы чихаете или смотрите на компилятор смешно, вы будете иметь дело несвязанный доступ к памяти.

И я должен подчеркнуть, что хотя гипотетический компилятор не требует разыменования указателя класса, он разрешен, и может потребоваться любой конкретной реализацией компилятора.

Дальнейшее чтение ... проверьте принятый ответ Разница между объектом и экземпляром: C ++ Ваш указатель класса вряд ли будет рассматриваться до тех пор, пока вы не получите доступ к instance data, связанному с конкретным экземпляром класса.

Или ... другой способ сложить все это Если вы можете добавить static перед объявлением функции, вызов с недопустимым указателем может сработать.

Смотри также:

class MyClass
{
public:
  int doSomething(int x)
  {
    printf("%d", x);
    return x;
  }
};

int main()
{
  MyClass *pMyClass = nullptr;
  pMyClass->doSomething(42);
}
...