Получение вектора <Полученный*> в функцию, которая ожидает вектор <Основа*>

Указатель NULL - это тот, который указывает на никуда. Когда вы разыскиваете указатель p, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p является нулевым указателем, местоположение, хранящееся в p, является nowhere, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception.

В общем, это потому, что что-то не было правильно инициализировано.

26
задан Coding Mash 9 September 2012 в 16:20
поделиться

9 ответов

vector<Base*> и vector<Derived*> несвязанные типы, таким образом, Вы не можете сделать этого. Это объяснено в C++ FAQ здесь .

необходимо заменить переменную от vector<Derived*> к vector<Base*> и вставить Derived объекты в нее.

кроме того, чтобы не копировать vector излишне, необходимо передать его ссылкой константы, не значением:

void BaseFoo( const std::vector<Base*>& vec )
{
    ...
}

Наконец, чтобы избежать утечек памяти и сделать Ваш код безопасным от исключения, рассматривают использование контейнера, разработанного для обработки выделенных "куче" объектов, например:

#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;

, С другой стороны, изменяют вектор для содержания интеллектуального указателя вместо того, чтобы использовать необработанные указатели:

#include <memory>
std::vector< std::shared_ptr<Base*> > vec;

или

#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;

В каждом случае, необходимо было бы изменить Ваш BaseFoo функция соответственно.

44
ответ дан j b 28 November 2019 в 06:07
поделиться

Вместо того, чтобы передать контейнерный объект (vector<>), передайте в begin и end итераторы как остальная часть алгоритмов STL. Функция, которая получает их, будет шаблонной, и не будет иметь значения, если Вы передадите в Полученном* или Base*.

24
ответ дан Frank Krueger 28 November 2019 в 06:07
поделиться

Эта проблема происходит на языках программирования, которые имеют изменяемые контейнеры. Вы не можете раздать изменяемый мешок яблок как мешок фруктов, потому что Вы не можете быть уверены, что кто-то еще не помещает лимон в тот мешок фруктов, после которых это больше не квалифицирует как мешок яблок. Если бы мешок яблок не был изменяем, раздав его, поскольку мешок фруктов был бы прекрасен. Поиск ковариантности/контравариантности.

14
ответ дан 28 November 2019 в 06:07
поделиться

одна опция состоит в том, чтобы использовать шаблон

template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
 ...
}

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

Редактирование, я должен отметить причину, нам нужен шаблон, вот то, потому что мы пытаемся записать тот же код для несвязанных типов, как отмечено несколькими другими плакатами. Шаблоны позволяют Вам, действительно решают эти точные проблемы. Я также обновил его для использования ссылки константы. Необходимо также передать "тяжелые" объекты как вектор ссылкой константы, когда Вам не нужна копия, которая является в основном всегда.

8
ответ дан Matt Price 28 November 2019 в 06:07
поделиться

Обычно Вы запускали бы с контейнера указателей базы, не другого пути.

2
ответ дан Greg Rogers 28 November 2019 в 06:07
поделиться

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

// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);

// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
 ...
}

// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );
2
ответ дан Community 28 November 2019 в 06:07
поделиться

Если Вы имеющий дело со сторонней библиотекой, и это - Ваша единственная надежда, то можно сделать это:

BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));

Иначе фиксируют Ваш код с одним из других предложений.

1
ответ дан eduffy 28 November 2019 в 06:07
поделиться

Если бы std::vector поддерживал то, что Вы просите, то было бы возможно победить систему типов C++, не используя бросков (редактирование: ссылка ChrisN на FAQ C++ Облегченные переговоры о той же проблеме):

class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};

void pushStuff(std::vector<Base*>& vec) {
    vec.push_back(new Derived2);
    vec.push_back(new Base);
}

...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!

Начиная с Вашего BaseFoo() функция берет вектор значением, это не может изменить исходный вектор, что Вы передали в, поэтому что я записал, не будет возможно. Но если это берет ссылку неконстанты, и Вы используете reinterpret_cast<std::vector<Base*>&>() для передачи Вашего std::vector<Derived*>, Вы не могли бы получить результат, который Вы хотите, и Ваша программа могла бы отказать.

поддержка массивов Java ковариантное выделение подтипов , и это требует, чтобы Java к сделал тип выполнения проверяет каждый раз, когда Вы храните значение в массиве . Это также - нежелательный.

1
ответ дан bk1e 28 November 2019 в 06:07
поделиться

Они - несвязанные типы - Вы не можете.

0
ответ дан Lou Franco 28 November 2019 в 06:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: