Использование производной функции от объекта внутри объекта списка

У меня есть два класса, один из которых наследует другой:

class baseClass
{
public:
    virtual void show();
};

void baseClass::show(){cout << "Base class" << endl;}


class derivedClass
{
public:
    void show();
};

void derivedClass::show(){cout << "Derived class" << endl;}

Если я создаю объект производного класса и вызываю функцию показа, он правильно печатает «Производный класс». Если я сделаю следующее:

derivedClass b;
baseClass* b;
b=&d;
b->show();

Он снова правильно выводит «Производный класс». Однако, если я составлю такой список:

list<baseClass> t;
list<baseClass>::iterator it;
baseClass b;
derivedClass d;
t.push_back(b);
t.push_back(d);

И попробуйте вызвать show для каждого элемента:

it = t.begin();
it->show();
it++;
it->show();

Результатом для b и d является «Базовый класс». Мой вопрос: почему он использует только версию show() базового класса и как я могу заставить его правильно использовать производную версию для объектов производного класса в списке?

заранее спасибо


person James    schedule 18.09.2011    source источник


Ответы (2)


Вы должны объявить метод show() как virtual, чтобы полиморфизм работал:

class baseClass
{
public:
    virtual void show();
};

void baseClass::show(){cout << "Base class" << endl;}


class derivedClass : public baseClass
{
public:
    virtual void show();
};

void derivedClass::show(){cout << "Derived class" << endl;}

Вам также не хватало class derivedClass : public baseClass.

И последняя проблема. Вам нужно использовать указатели.

list<baseClass*> t;
list<baseClass*>::iterator it;
baseClass b;
derivedClass d;
t.push_back(&b);
t.push_back(&d);

и изменить на это:

it = t.begin();
(*it)->show();
it++;
(*it)->show();
person Mysticial    schedule 18.09.2011
comment
Плохо, это была ошибка в вопросе (который я отредактировал), show() был виртуальным в базовом классе. Я попытался сделать show() виртуальным в производном классе, как вы сказали, но он все еще не вызывает правильную функцию. - person James; 18.09.2011
comment
Я получаю тот же результат, что и вы. Это как-то связано с итератором. Дай мне секунду, чтобы обновить мой ответ. - person Mysticial; 18.09.2011
comment
Большое спасибо, (*это) была часть, на которой я постоянно застревал (пробовал *это и *(это) вчера ›.‹) Теперь работает отлично - person James; 18.09.2011

Он снова правильно выводит «Производный класс». Однако, если я составлю такой список:

Нет. Он не может печатать «Производный класс». На самом деле эта строка:

b=&d;

выдаст ошибку компиляции, поскольку b не является полиморфной основой d.

Объявите show как virtual в базовом классе:

virtual void show();

Тогда это скомпилируется.

Однако даже после создания show виртуального помещение объекта производного класса в список приведет к разбиению объектов, поскольку список может содержать только объекты базового класса; это означает, что список получит подобъект объекта производного класса. Это потому, что вы объявили список как:

list<baseClass> t;

что не правильно.

Объявите это как:

list<baseClass*> t;

и нажмите pointer, чтобы возразить против этого, например:

derivedClass d;
derivedClass *pd = new derivedClass;
baseClass b;

t.push_back(&d);
t.push_back(pd); //note there is no `&`
t.push_back(&b);

//use t

//must delete pd
delete pd;

--

Просто обратите внимание, что если вы хотите удалить объекты производного класса, используя указатель типа базового класса, что-то вроде этого:

baseClass *bptr = new derivedClass();
delete bptr;

тогда вы должны определить деструктор baseClass как виртуальный, иначе оператор удаления выше вызовет неопределенное поведение.

Итак, сделайте следующее:

class  baseClass:
{
  //...
  virtual ~baseClass();
};
person Nawaz    schedule 18.09.2011
comment
Не могли бы вы уточнить, что вы подразумеваете под указателем вставки, чтобы возразить против этого? Кроме того, если я попробую list‹baseClass*› t; list‹baseClass*›::iterator it; t.push_back(&b); t.push_back(&d); Затем это-›show(); выдает ошибку (выражение должно иметь указатель на тип класса) - person James; 18.09.2011
comment
@Alexdander: отредактировал сообщение. Смотрите сейчас. - person Nawaz; 18.09.2011
comment
Большое спасибо за помощь, использовал ваши ответы и Mysticial вместе, и это сработало как шарм =) - person James; 18.09.2011