Преобразование между различными деревьями классов в C ++ - PullRequest
3 голосов
/ 29 ноября 2011

Следующий код, кажется, работает с компиляторами (clang, g ++ на обоих, Linux и Mac OS), которые я пробовал, но гарантированно ли он всегда будет делать то, что и следовало ожидать?

struct A {
  virtual void foo() = 0;
};

struct A2 {
  virtual void foo() = 0;
};

struct B : public A2 {
  void foo() {
    printf("test\n");
  }
};

int main() {
  B* b = new B;
  ((A*)b)->foo();
}

Я понимаюэто плохая практика, и не следует этого делать, но работает ли она вообще?

Ответы [ 3 ]

6 голосов
/ 29 ноября 2011

Если ожидать неопределенного поведения, то оно гарантировано.

4 голосов
/ 29 ноября 2011

Это неплохая практика: она не работает . Это будет делать что-то все в порядке. Не исключено, что сбой. Это все разрешено, поскольку вы вызываете неопределенное поведение . Редактировать Вы можете обратиться к технической документации вашего компилятора ( см. ABI ), чтобы найти специфичные для компилятора расширения , на которые вы могли бы положиться.

Попробуйте использовать

static_cast<A*>(b)    // invalid static cast (compile error)
dynamic_cast<A*>(b)   // returns null pointer value (runtime)

То, что вы делаете, эффективно

  • reinterpret_cast<A*>(b)

и результаты полностью ваша ответственность определяется реализацией .

Редактировать Навазу: соответствующий отрывок стандартов: § 5.2.10, пункт

7. Указатель на объект может быть явно преобразован в указатель на объект другого типа. 69 Когда prvalue v типа «указатель на T1» преобразуется в тип «указатель на cv T2», результат равен static_cast<cv T2*>(static_cast<cv void*>(v)), если T1 и T2 имеют стандартную компоновку типы (3.9) и выравнивание требования T2 не более строгие, чем требования T1. Преобразование prvalue типа «указатель на T1» в тип «указатель на T2» (где T1 и T2 являются типами объектов и где требования к выравниванию T2 не более строгие, чем требования к T1) и обратно в его оригинальный тип возвращает исходное значение указателя. Результат любого другое такое преобразование указателя не определено .

3 голосов
/ 29 ноября 2011

Если вы используете приведение в стиле C ++, то вы сразу увидите проблему:

(static_cast<A*>(b))->foo();  //compile-time error
(dynamic_cast<A*>(b))->foo(); //runtime error

Демонстрация: http://ideone.com/LZjrx (ошибка времени компиляции)
Демонстрация: http://ideone.com/ePIfO (ошибка времени выполнения)

Поскольку static_cast выдает ошибку компиляции, история заканчивается прямо во время компиляции. Когда dynamic_cast, тогда приведение возвращает null, для которого вы пытаетесь вызвать foo, поэтому вы получаете ошибку времени выполнения.

Даже если вы не знаете, какие приведения использовать, эти две приведения дают достаточно уверенности, чтобы сомневаться в коде, в то время как использование reinterpret_cast настолько редко, что я даже не рассматриваю здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...