Полиморфизм и указатели на массивы [дублировать]
-
05-07-2019 - |
Вопрос
На этот вопрос уже есть ответ здесь:
У меня есть класс А:
class A
{
public:
virtual double getValue() = 0;
}
И класс В:
class B : public A
{
public:
virtual double getValue() { return 0.0; }
}
И затем в main() я делаю:
A * var;
var = new B[100];
std::cout << var[0].getValue(); //This works fine
std::cout << var[1].getValue(); //This, or any other index besides 0, causes the program to quit
Если вместо этого я сделаю:
B * var;
var = new B[100];
std::cout << var[0].getValue(); //This works fine
std::cout << var[1].getValue(); //Everything else works fine too
Все компилируется нормально, но, возможно, кажется, что с моим полиморфизмом что-то не так?Я озадачен.
Решение
Вы не можете обрабатывать массивы полиморфно, поэтому, хотя new B[100]
создает массив B
объектов и возвращает указатель на массив - или, что эквивалентно, на первый элемент массива - и хотя допустимо присваивать этот указатель указателю на базовый класс, недопустимо рассматривать это как указатель на массив A
Объекты.
Основная причина, по которой вы не можете этого сделать, заключается в том, что (обычно) производные объекты имеют размер, отличный от их базовых классов, поэтому попытка доступа к массиву как к массиву объектов базового класса не будет использовать правильное смещение для получения указателя на следующий подобъект базового класса следующего члена массива производного класса.
Другие советы
Проблема не в полиморфизме, а в том, как вы работаете с памятью.Оператор [] продвинет вас по массиву на размер байт (A) в первом случае и на размер байт (B) во втором случае.Поскольку объекты относятся к типу B, A * не указывает на правильное местоположение в памяти.
Вот еще один способ взглянуть на это
char * var;
var = (char*) new B[100];
std::cout << ((A*)var[0]).getValue(); //This works fine
std::cout << ((A*)var[1]).getValue(); //This will fail
std::cout << ((A*)var[sizeof(B)]).getValue(); // should work
Вы не выделили объекты в массиве:
for (int i=0;i<100;i++)
var[i] = new B;
(хотя, возможно, я путаю C ++ и C #)