﻿# V777\. A dangerous widening type conversion from an array of derived class objects to a base class pointer\.

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

Рассмотрим пример такого кода:

```cpp
class Base
{
  int buf[10];

public:
  virtual void Foo() { ... }
  virtual ~Base() { }
};

class Derived : public Base
{
  char buf[10];

public:
  virtual void Foo() override { ... }
  virtual ~Derived() { }
};

....
size_t n = 5;
Base *ptr = new Derived[n];   // <=
....
for (size_t i = 0; i < n; ++i)
  (ptr + i)->Foo();
....
```

В примере объявлены базовый класс "Base" и производный от него "Derived"\. Каждый объект этих классов будут занимать в памяти 48 и 64 байта соответственно \(вследствие выравнивания классов по ширине 8 байт; компилятор MSVC, 64\-bit\)\. При "i  \>\= 1" для обращения к ненулевому элементу необходимо каждый раз перемещать указатель на "i \* 64" байта, но, поскольку массив адресуется указателем на базовый класс Base, смещение на самом деле будет вычисляться как "i \* 48" байт\.

Так должно было вычисляться смещение указателя:

![V777_ru/image1.png](https://import.viva64.com/docx/blog/V777_ru/image1.png)

Однако вычислено смещение указателя будет так:

![V777_ru/image2.png](https://import.viva64.com/docx/blog/V777_ru/image2.png)

Фактически, программа начинает работать с объектами, содержащими случайный набор данных\.

Корректный вариант кода:

```cpp
....
size_t n = 5;
Derived *ptr = new Derived[n];   // <=
....
for (size_t i = 0; i < n; ++i)
  (ptr + i)->Foo();
....
```



Ошибочно также приводить указатель на указатель на производный класс к указателю на указатель на базовый класс:

```cpp
....
Derived arr[3];
Derived *pDerived = arr;
Class5 **ppDerived = &pDerived;
....
Base **ppBase = (Derived**)ppDerived; // <=
....
```

Для правильного хранения массива объектов производного класса полиморфически необходимо размещать объекты следующим образом:

![V777_ru/image3.png](https://import.viva64.com/docx/blog/V777_ru/image3.png)

Корректный код при этом будет выглядеть следующим образом:

```cpp
....
size_t n = 5;
Base **ppBase = new Base*[n]; // <=

for (size_t i = 0; i < n; ++i)
  ppBase[i] = new Derived();
....
```



Если мы хотим подчеркнуть, что будем работать только с одним объектом, то можно написать так: 

```cpp
....
Derived *derived = new Derived[n];
Base *base = &derived[i];
....
```

Такой код считается анализатором безопасным, и он не выдаёт предупреждение\.

Не является также ошибкой применение указателя, который адресуется на массив объектов производного класса, содержащий один элемент\.

```cpp
....
Derived arr[1];
Derived *new_arr = new Derived[1];
Derived *malloc_arr = static_cast<Base*>(malloc(sizeof(Derived)));
....
Base *base = arr;
base = new_arr;
base = malloc_arr;
....
```



Примечание\. В случае одинакового размера базового и производного классов допускается адресоваться на массив объектов производного класса указателем на базовый класс, однако так делать не рекомендуется\.