Допустим, у меня есть пустой класс с виртуальной функцией:
class Base
{
public:
virtual void Foo(){std::cout << "this is the base class";}
}
Тогда у меня есть класс, который наследует от Base
и переопределяет Foo()
:
class Derived : public Base
{
public:
void Foo(){std::cout << "this is the derived class";}
}
Тогда есть какой-то другой класс, который содержит список Base
:
class OtherClass
{
public:
std::vector<Base> listOfBases; //note it's not std::list<Derived>
}
Как мне перебрать listOfBases
и позвонить Foo()
для Derived
класс не тот Base
учебный класс? Прямо сейчас, если бы я должен был сказать, listOfBases[i].Foo();
затем это базовый класс будет печатать, но я хочу переопределить один из Derived
класс для печати.
Я мог бы просто составить список Derived
вместо Base
и это все исправит, но я буду называть эти унаследованные классы разными вещами, поэтому мне нужен список Base
,
Итак, как мне вызвать переопределенную функцию из списка ее базового класса?
Вам нужно использовать список Base*
(то есть указатели на базу) или, предпочтительно, std::unique_ptr<Base>
или же std::shared_ptr<Base>
,
Причина этого кроется в объектной модели C ++ и ее копировании. Производные классы должны быть как минимум такого же размера, как и их базовый класс (они могут быть одинакового размера в зависимости от того, является ли производный класс пустым или нет). Поскольку C ++ использует копирование (или, возможно, перемещение в C ++ 11) при добавлении элементов в vector
, он должен выделить достаточно места для п Base
объекты. Так как vector
почти всегда обертка вокруг простого array
, пытаясь добавить (возможно, другого размера) Derived
возражать в array
из Base
объекты неопределенного поведения.
Получите указатель на каждый базовый класс, а затем уменьшите его до производного класса. Это называется downcast, потому что в UML-диаграмме принято рисовать базовый класс над производным классом.
for ( auto q = listOfBases.begin(); q != listOfBases.end(); ++q )
{
Base* pBase = &(*q); // Get pointer to Base class. Can't downcast on object.
Derived* pDerived = dynamic_cast<Derived*>(pBase); // Downcast
pDerived->Foo(); // Call Foo() of Derived
}