Попытка запомнить основной материал C++ (это было долгое время) и играть с компилятором. Я создал простой пример базового/дочернего наследования.
Я ожидал, что ниже выйдет
index 0 is 0
index 1 is 1
index 2 is 2
но вместо этого получите:
index 0 is 0
index 1 is 2
index 2 is 0
Может кто-то указать, что, очевидно, является плохой ошибкой с моей стороны?
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <string>
using namespace std;
class Base
{
public:
Base(){x=0;}
int x;
};
class Derived : public Base
{
public:
Derived() { y=0;}
int y;
};
// practicing operator definition syntax
ostream& operator<<(ostream& ostr, const Base& base)
{
ostr << base.x << endl;
ostr << flush;
return ostr;
}
void init(Base *b)
{
for (int i = 0; i<3; i++)
{
b[i].x=i;
}
};
int main(int argc, char** argv)
{
Derived arr[3];
init(arr);
for (int idx = 0; idx< 3; idx++)
{
cout << "index is " << idx << ' ' << arr[idx] << endl;
}
return 0;
}
Массивы и полиморфизм не смешиваются в C++.
Derived
и Base
объекты имеют разные размеры, любая арифметика указателя, участвующая в вашей программе, терпит неудачу.
Ваш метод init
нарезает Derived
объекты в Base
объектах. Следующее присваивание имеет неопределенное поведение, оно устанавливает некоторые байты где-то на объекте Derived
.
Рассмотрите возможность использования std::vector<std::unique_ptr<B>>
в качестве замены.
Кроме того, в вашем Base
классе отсутствует его виртуальный деструктор, который вызывает более неопределенное поведение позже.
Массив для производного типа не является массивом базового типа! Хотя указатель на производные объекты преобразуется в указатель на базовый объект, вы не можете использовать базовый указатель в качестве указателя в массив базовых объектов.
Обоснование довольно просто: когда вы выполняете операцию типа array[i]
компилятор переводит это значение в *(array + i)
а внутренняя арифметика адресов выполняется как нечто вроде array + sizeof(T) * i
где T
- статический тип array
. Теперь, для типа D
полученного из базового типа B
он обычно имеет sizeof(B) < sizeof(D)
. В результате, если вы обрабатываете массив производных объектов как массив основанных объектов, то арифметика индекса приведет к доступу элементов в более или менее случайных местах объекта.
init
?