список полиморфных объектов

У меня есть конкретный сценарий ниже. Приведенный ниже код должен печатать функцию «say ()» класса B и C и печатать «B говорит ...» и «C говорит ...», но это не так. Любые идеи. Я изучаю полиморфизм, поэтому также прокомментировал несколько вопросов, связанных с ним, в строках кода ниже.

class A
{
public:
// A() {}
    virtual void say() { std::cout << "Said IT ! " << std::endl; }
    virtual ~A(); //why virtual destructor ?
};

void methodCall() // does it matters if the inherited class from A is in this method
{
    class B : public A{
    public:
        // virtual ~B(); //significance of virtual destructor in 'child' class
        virtual void say () { // does the overrided method also has to be have the keyword  'virtual'
            cout << "B Sayssss.... " << endl; 
        }
    };
    class C : public A {
    public:
        //virtual ~C();
        virtual void say () { cout << "C Says " << endl; }
    };

    list<A> listOfAs;
    list<A>::iterator it;

    # 1st scenario
    B bObj; 
    C cObj;
    A *aB = &bObj;
    A *aC = &cObj;

    # 2nd scenario
    //  A aA;
    //  B *Ba = &aA;
    //  C *Ca = &aA; // I am declaring the objects as in 1st scenario but how about 2nd   scenario, is this suppose to work too?

    listOfAs.insert(it,*aB);
    listOfAs.insert(it,*aC);

    for (it=listOfAs.begin(); it!=listOfAs.end(); it++)
    {
        cout <<  *it.say()  << endl;
    }
}

int main()
{
    methodCall();
    return 0;
}

person mu_sa    schedule 11.02.2012    source источник


Ответы (3)


Ваша проблема называется нарезка, и вы должны проверить этот вопрос: Изучение C++: полиморфизм и нарезка

Вы должны объявить этот список как список указателей на As:

list<A*> listOfAs;

а затем вставьте в него эти указатели aB и aC вместо создания копий объектов, на которые они указывают. То, как вы вставляете элементы в список, неверно, вам лучше использовать функцию push_back для вставки:

B bObj; 
C cObj;
A *aB = &bObj;
A *aC = &cObj;

listOfAs.push_back(aB);
listOfAs.push_back(aC);

Тогда ваш цикл может выглядеть так:

list<A*>::iterator it;
for (it = listOfAs.begin(); it != listOfAs.end(); it++)
{
    (*it)->say();
}

Выход:

B Sayssss....
C Says

Надеюсь это поможет.

person LihO    schedule 11.02.2012
comment
На самом деле использование контейнера голых указателей - это осиное гнездо Пандоры, и что угодно может пойти не так... - person Kerrek SB; 11.02.2012
comment
Я согласен. Но в данном случае я считаю более целесообразным использовать голые указатели, чтобы он лучше понимал, что там происходит. - person LihO; 11.02.2012
comment
в приведенном выше сценарии я должен также позаботиться об элементах списка, как только я его использовал. Должен ли я удалить его или что-то в этом роде??? - person mu_sa; 15.02.2012
comment
В этом списке есть ссылки на автоматические переменные (bObj и cObj), поэтому нет. Вы не удаляете его, так как вы его не выделили. - person LihO; 15.02.2012

Полиморфизм иерархий виртуальных классов работает только через ссылки или указатели на базовый подобъект:

struct Der : Base { /* ... */ };

Der x;

Base & a = x;

a.foo();   // calls Der::foo() from x

Функция foo диспетчеризируется полиморфно, если это виртуальная функция в Base; полиморфизм относится к тому факту, что когда вы вызываете функцию-член объекта типа Base, функция, которая фактически вызывается, может быть реализована в классе Der.

Контейнеры могут хранить только элементы фиксированного типа. Чтобы хранить полиморфную коллекцию, вы могли бы вместо этого иметь контейнер указателей на базовый класс. Поскольку вам нужно хранить фактические объекты в другом месте, управление временем жизни нетривиально, и лучше оставить его специальной оболочке, такой как unique_ptr:

#include <list>
#include <memory>


int main()
{
    std::list<std::unique_ptr<Base>> mylist;

    mylist.emplace_back(new Der1);
    mylist.emplace_back(new Der2);
    // ...

    for (p : mylist) { p->foo(); /* dispatched dynamically */ }
}
person Kerrek SB    schedule 11.02.2012
comment
1 : Что делает этот Контейнер может хранить только элементы фиксированного типа. означает ?? 2: вместо этого вы могли бы иметь контейнер указателей на базовый класс. Вы имеете в виду «list‹A *› listOfAs» ​​вместо «list‹A› listOfAs;» - person mu_sa; 15.02.2012

list::iterator it; B bObj; C cObj; A *aB = &bObj; A *aC = &cObj; listOfAs.insert(it,*aB);

Вам не нужно инициализировать «это»? Я считаю, что вы должны это сделать = listOfAs.begin(); перед началом вставки.

person Sharad    schedule 11.02.2012