Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
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
функция соответственно.
Вместо того, чтобы передать контейнерный объект (vector<>
), передайте в begin
и end
итераторы как остальная часть алгоритмов STL. Функция, которая получает их, будет шаблонной, и не будет иметь значения, если Вы передадите в Полученном* или Base*.
Эта проблема происходит на языках программирования, которые имеют изменяемые контейнеры. Вы не можете раздать изменяемый мешок яблок как мешок фруктов, потому что Вы не можете быть уверены, что кто-то еще не помещает лимон в тот мешок фруктов, после которых это больше не квалифицирует как мешок яблок. Если бы мешок яблок не был изменяем, раздав его, поскольку мешок фруктов был бы прекрасен. Поиск ковариантности/контравариантности.
одна опция состоит в том, чтобы использовать шаблон
template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
...
}
, недостаток состоит в том, что реализация должна быть в заголовке, и Вы получите немного чрезмерного увеличения размера кода. Вы будете волновать с различными функциями, инстанцируемыми для каждого типа, но код остается таким же. В зависимости от варианта использования это - быстрое и грязное решение.
Редактирование, я должен отметить причину, нам нужен шаблон, вот то, потому что мы пытаемся записать тот же код для несвязанных типов, как отмечено несколькими другими плакатами. Шаблоны позволяют Вам, действительно решают эти точные проблемы. Я также обновил его для использования ссылки константы. Необходимо также передать "тяжелые" объекты как вектор ссылкой константы, когда Вам не нужна копия, которая является в основном всегда.
Обычно Вы запускали бы с контейнера указателей базы, не другого пути.
Взятие 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 );
Если Вы имеющий дело со сторонней библиотекой, и это - Ваша единственная надежда, то можно сделать это:
BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));
Иначе фиксируют Ваш код с одним из других предложений.
Если бы 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 к сделал тип выполнения проверяет каждый раз, когда Вы храните значение в массиве . Это также - нежелательный.