2015-03-10 3 views
3

Я пытаюсь назначить производные объекты вектору базовых объектов, а затем отбрасывать их обратно на производные объекты. Однако я не могу сделать бросок.динамическое литье базы на производные объекты

struct Base 
{ 
    string foo; 
    virtual ~Base() {} 
}; 

struct Derived : Base 
{ 
    string bar; 
}; 

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

void foo(vector<Base> &bases) 
{ 
    Base *base; 
    if (...) 
    { 
     base = new Derived; 
     base->foo = string("hello"); 
    } 
    bases.push_back(*base) 
} 

Тогда я прохожу в векторе к этой функции и попытаться получить его содержимое.

vector<Base> bases; 
foo(bases); 

for (auto it = bases.begin(); it != bases.end(); ++it) 
{ 
    Base *base = &(*it); 
    Derived *derived = dynamic_cast<Derived*>(base); 
    // derived == nullptr 
} 

Что мне здесь не хватает? Если я пытаюсь получить доступ к foo в качестве базового объекта, он работает, но когда я пытаюсь динамически преобразовать объект Derived, он терпит неудачу, несмотря на то, что был создан как объект Derived в функции foo(vector<Base> &bases).

+1

См. Раздел «Нарезка объектов». – chris

+1

Вы не можете использовать 'vector ', вы в конечном итоге срезаете объекты 'Derived', которые вы вставляете в него. Вместо этого используйте 'vector >'. – Praetorian

ответ

2

Это не будет работать:

void foo(vector<Base> &bases) 
{ 
    Base *base; 
    if (...) 
    { 
     base = new Derived; 
     base->foo = string("hello"); 
    } 
    bases.push_back(*base) 
} 

vector<> содержит объекты, а не ссылки. Когда вы используете push_back объект, который, как предполагается, имеет базовый тип, сохраняются только данные, которые применимы к базовому типу (то есть, «нарезанный»).

Вместо этого храните Base* или shared_ptr<Base> в vector<>.

Следует также отметить, что в приведенном выше фрагменте вы можете получить доступ к нарушениям всякий раз, когда блок if() пропускается, так как base никогда не инициализируется.

0

Проблема в том, что вы не можете использовать полиморфизм с объектами напрямую, вы должны использовать POINTERS базовых объектов, а затем вы можете применять к производным классам или напрямую обращаться к виртуальным методам.

Измените вашу систему от:

vector<Base> bases; 

в

vector<Base*> bases; 

и обновить весь код в основе этого, и все будет работать отлично :)

+0

«все будет работать отлично» - помимо необходимости хранить объекты где-то и управлять их сроками службы. –

+0

«... обновить весь ваш код в базе этого ...«суммирует это;) – Drewen

0

Ваш вектор содержит Base объекты , типа Base. Возможно, вы инициализировали их, скопировав производные типы; но все, что было сделано, это скопировать часть Base (которую некоторые люди называют нарезкой), теряя всякое знание исходных типов.

Полиморфизм работает только со ссылками или указателями; вам понадобится Base* для управления объектами производных типов. Как управлять временем жизни самих объектов, либо храниться где-то в другом месте, либо с помощью указателей вектора (предпочтительно умных), которыми они владеют, остается как упражнение.

Смежные вопросы