#c
#c
Вопрос:
У меня есть виртуальный класс basic_action
. Класс sippeers
наследует class basic_action
. Для хранения экземпляров sippeers
классов, которые я использую boost::ptr_list
. Вот пример кода:
boost::ptr_list<basic_action> ActionsList;
sippeers spclass;
ActionsList.push_back(amp;spclass);
basic_action *sp = ActionsList.front();
Здесь я создаю экземпляр prt_list
с указателями на экземпляры моих basic_action
классов.
Затем я создаю новый экземпляр моего sippeers
класса.
Затем я вставляю указатель на sippeers
класс в ptr_list
.
Последняя строка завершается ошибкой.
Не удается преобразовать ‘basic_action’ в ‘basic_action *’.
Но basic_action *
внутри есть, а не basic_action
!
Комментарии:
1. Это не имеет отношения к вашему вопросу, но контейнеры с указателями boost становятся владельцами объектов, которые вы в них помещаете. Вы не хотите помещать объект, выделенный стеком, в ptr_list.
Ответ №1:
boost::ptr_list::front()
возвращает ссылку на шаблонный тип, а не указатель.
Итак, в этом случае он возвращает basic_actionamp;
.
Смотрите документацию здесь для ptr_sequence_adapter
, из которой ptr_list
является производным.
Итак, ваш код должен гласить:
boost::ptr_list<basic_action> ActionsList;
sippeers spclass;
ActionsList.push_back(amp;spclass);
basic_action amp;sp = ActionsList.front();
Комментарии:
1. boost::ptr_list::front() возвращает ссылку. Последняя строка должна быть: basic_actionamp; sp = ActionsList.front();
2. @Ferruccio Спасибо — поймал мою опечатку и отредактировал около 7 минут назад. 🙂
Ответ №2:
ptr_list::front() возвращает ссылку на первый объект в списке. Если бы basic_action был конкретным типом, вы могли бы выполнить оба следующих действия.
// 1
basic_actionamp; sp = ActionsList.front();
// 2
basic_action sp = ActionsList.front();
# 1 сделал бы sp ссылкой на первый объект в списке. Другими словами, любые изменения, внесенные вами через sp, также изменят первый объект в списке.
# 2 создаст экземпляр нового объекта basic_action и скопирует содержимое первого объекта в списке в этот новый объект. Любые изменения в нем не повлияют на первый элемент в списке.
Если basic_action является абстрактным классом, опция # 2 вам больше недоступна, потому что вы не можете создавать экземпляры объектов абстрактного класса.
кроме того, вы не должны помещать объекты, выделенные стеком, в контейнер указателя boost. Плохие вещи произойдут, когда ptr_list выйдет за пределы области видимости и попытается удалить все содержащиеся в нем объекты. Вместо этого сделайте что-то вроде:
boost::ptr_list<basic_action> ActionsList;
ActionsList.push_back(new sippeers);
basic_actionamp; sp = ActionsList.front();
Ответ №3:
Если вы посмотрите на заголовок, то увидите, что:
template
<
class T,
class VoidPtrSeq,
class CloneAllocator = heap_clone_allocator
>
class ptr_sequence_adapter
{
public: // construct/copy/destroy
template< class InputIterator >
assign( InputIterator first, InputIterator last );
template< class InputRange >
assign( const InputRangeamp; e );
public: // element access
Tamp; front();
(Примечание; ptr_list напрямую наследуется от ptr_sequence_adapter) Итак, вы получаете тип, а не ссылку на тип; он выполняет автоматическое разыменование для вас:
basic_action sp = ActionsList.front();
правильно.
Комментарии:
1. Я пытался использовать этот код, но Visual Studio выдает ошибку: ошибка C2259: ‘basic_action’: не удается создать экземпляр абстрактного класса.
2. @CagoBHuK: это потому, что это неверно. Вам повезло, что вы получаете еще одну ошибку компилятора, а не странное поведение из-за непреднамеренного нарезания.
3. @CagoBHuK: проблема в том, что boost::ptr_list::front() возвращает ссылку. Вы можете назначить его ссылке (basic_action amp; sp = …), но без ссылки он попытается скопировать объект, на который ссылается, в новый объект basic_action (который он не может создать, потому что это абстрактный тип)