Использование указателя на базовый класс в качестве параметра массива - PullRequest
0 голосов
/ 27 января 2010

У меня есть 2 класса:

class Base
{
public:
     virtual int Foo(int n);
         virtual void Goo() = 0;
     virtual ~Base() ;
};


class Derived : public Base
{
public:
    int Add4Bytes;

        void Goo();
    int  Foo(int n);    
};

int Test(Base* b)
{
    for (int i=0;i<5;++i)
    {
        b->Foo(i);
        ++b;
    }
    return 0;
}

void Test2(Base arr[])
{
    for (int i=0;i<5;++i)
    {
        arr[i].Foo(i);
    }
}

void main
{

      Base* b = new Derived[5];
      Test(b);
}

Итак, когда я вызываю Test, после второго цикла возникает исключение из-за потери памяти.

У меня есть 2 вопроса:

  1. В чем разница между аргументом функции в Test и Test2? (Test2 не компилируется после того, как я превратил Base в чистый абстрактный класс).

и более важный вопрос

  1. Как я могу предотвратить это исключение и как я могу передать массив производного класса в функцию, которая должна получить массив базового класса. (я не могу сказать во время компиляции, какой производный класс я собираюсь передать функции)

p.s - пожалуйста, не говорите мне читать книгу Мейерса, именно поэтому я и задаю этот вопрос. :)

Спасибо

Ответы [ 4 ]

4 голосов
/ 27 января 2010

Нет разницы между типами параметров, параметры массива настраиваются на указатели в объявлениях функций.

Хотя вы можете преобразовать указатель в Derived в указатель на Base, вы не можете рассматривать массив Derived как массив Base, они не являются связанными типами. Это связано с тем, что в массиве Derived класс Base является подобъектом Derived, а не частью массива Base. Когда вы выполняете арифметику указателей, как если бы она была частью массива Base, вы получаете неопределенное поведение, вы, вероятно, создадите указатель Base, который точно не указывает на начало Base объекта.

3 голосов
/ 27 января 2010

Массивы плохо работают с полиморфными типами в качестве содержимого из-за нарезки объектов. Элемент массива имеет фиксированный размер, и если ваши производные объекты имеют больший размер, чем базовый, то массив базовых объектов не может фактически содержать производные объекты.

Даже если параметр функции может переходить в указатель, арифметика указателя, выполненная для этого указателя, будет основываться на размере элемента типа массива.

Чтобы иметь дело с массивами полиморфных типов, вам нужно добавить еще один уровень косвенности и иметь дело с массивами (или другим контейнером) указателей на объекты.

Test2 не компилируется после того, как я превратил Base в чистый абстрактный класс

Вы не можете иметь массивы абстрактных типов, потому что у вас не может быть экземпляров абстрактных типов (только указатели или ссылки на них).

1 голос
/ 27 января 2010

Ваша Test функция проходит через массив Base объектов, то есть шаг равен sizeof( Base ), тогда как он должен быть sizeof( Derived ). Вы, вероятно, хотите объявить это как:

int Test( const std::vector<Base*>& );
0 голосов
/ 27 января 2010

Дополнительную информацию о массивах базовых и производных классов можно найти в C ++ FAQ. Вопрос Lite 21.4: Является ли массив Derived своего рода массивом Base?

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