Проверка типов C ++ выполняется при назначении одного указателя другому - PullRequest
1 голос
/ 04 февраля 2020

Мне интересно, что расширение проверки типов выполняет компилятор в следующем

class Parent{
};

class Child : public Parent{
};

class Unrelated{
};

main(){
  Parent* p = new Child() // OK. But type of p is still Parent* and not Child*
  Unrelatead* u = new Child() // Not OK. Child* is not Unrelated*.
}

Итак, в первом присваивании p теперь указывает на объект 'Parent' внутри Child, тогда как второе присваивание вообще не допускается, хотя в конечном итоге и p, и u будут хранить адреса памяти.

Какие именно проверки выполняет компилятор во время этих назначений и в какой части компиляции эти проверки выполняются компилятором?

Ответы [ 2 ]

0 голосов
/ 04 февраля 2020

Первое назначение в порядке, потому что компиляторы организуют всю память базового класса перед памятью производного класса. Таким образом, вы можете отклонять указатели, так как все поля базового класса по-прежнему будут указывать.

Второе присваивание не в порядке, поскольку Child не наследуется от Unrelated, и поэтому их расположение в памяти может будь другим. Компилятор отслеживает эти иерархии классов. Эти проверки происходят только во время компиляции.

Обратите внимание, что указатели апскейдинга могут быть опасными. Если ваш класс не является виртуальным, delete p не вызовет деструктор производного класса, что приведет к потенциальным утечкам памяти. Если вы решите использовать upcast и delete указатели, убедитесь, что вы делаете это для виртуальных классов.

0 голосов
/ 04 февраля 2020

Компилятор позволяет назначать указатели данных:

  1. Когда оба являются указателями на один и тот же тип, или указатель назначения является указателем на более ограниченный const / volatile квалифицированный тип, например T* до T const volatile*.
  2. Указатель на производный класс может быть назначен указателю на доступный базовый класс с аналогичной или более ограничительной квалификацией const / volatile, например Derived* до Base const*.
  3. Любой указатель данных на void* с аналогичной или более ограничительной квалификацией const / volatile, например, T const* до void const*.

Parent* p = new Child(); компилируется потому что это случай 2.

Unrelatead* u = new Child(); не компилируется, потому что это не один из вышеперечисленных случаев. Для работы между несвязанными указателями данных требуется reinterpret_cast<>.

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