0

I have a generic linked list that works with various types of data including objects and pointers to objects, etc, but i'm having trouble working with the list when I insert objects from a class that is derived from an abstract class.

I have an abstract class called vehicle and 2 classes that are carr and truck and I can do something like this:

list<vehicle> lv;

vehicle * v1;
vehicle * v2;

v1 = new carr;
v2 = new truck;

cin >> *v1 >> *v2;

//But when I try to insert in the list

lv.insertEnd(*v1);

I have the error:

cannot allocate an object of abstract type 'vehicle'

And the compiler show that the error is in the insertEnd method of my linked list code in the part where I write:

newNode->item = new Item;

This a part of a project where I need to have a list of vehicles and the vehicles can be carrs, trucks, etc. I have the group of vehicles implemented with pointers to pointers but i'm trying to do this with a list of vehicles.

Can you help me?

EDIT: The item is in my linked list, i'll show my insertEnd method:

template <class Item>
void list<Item>::insertEnd(const Item& item)
{
    node<Item> *newNode= new node<Item>;

    newNode->item = new Item;
    *(newNode->item) = item;
    newNode->next = 0;

    if(head == 0)
    {
       head = newNode;
       tail = newNode;
        _size++;
    }
    else
    {
        novoNo->prev = tail;
        tail->next = newNode;
        tail = newNode;
         _size++;
    }
}
wormwood87
  • 153
  • 1
  • 3
  • 12
  • 1
    You're trying to insert `vehicle` instances into a container. But it's abstract. Recall that containers own their elements and thus copy their inputs. Read about slicing. – Lightness Races in Orbit Jan 07 '13 at 01:48
  • Are you trying to make a list of pointers or a list of objects? If `insertEnd` takes a `vehicle`, then it cannot take a `carr` or a `truck`, but only an instance of a `vehicle`. (Creating polymorphic collections is, unfortunately, quite irritating in C++. For one thing, there's no easy way to make a duplicate of an object given a reference or pointer to it.) – David Schwartz Jan 07 '13 at 01:53

3 Answers3

5

You are trying to store an item by value in your linked list. Using items by value breaks polymorphism: only pointers or references are polymorphic.

The reason this is the error you see is that you are dereferencing your pointer here: lv.insertEnd(*v1). Passing in a value this way will cause C++ to use the copy constructor for the type specified in insertEnd to make the object inside of your insertEnd function (check your code: the type of the parameter to insertEnd is surely the type specified in your template - which is vehicle here). By passing by value, you are telling your code to copy the whole of v1 into a new object inside of insertEnd. This falls apart, because vehicle is an abstract class: its copy constructor cannot be used to make a fully functional object, because it's abstract.

This sort of shadows what's really going on here: you can't pass around objects by value and expect them to be polymorphic. If you don't see this error, what will likely happen is that you will likely slice your object, which can be even worse to debug. Do what @billz recommends and use a smart pointer.

EDIT: after seeing your addition of your insertEnd code, where you are passing by reference, there is an addendum: the compiler is not going to call the copy constructor in insertEnd. Instead, you likely see the error on this line: newNode->item = new Item. Here you can see where you are trying to instantiate the abstract class. Replace the word 'Item' with 'vehicle' - that's what you're doing with your template - and you can see it very clearly.

In any case, passing-by-reference to a dereferenced pointer is a very painful and error-prone thing indeed. It's way too easy to introduce errors: if you delete v1 anywhere in your code, like a good programmer does (great ones use auto pointers), you are likely to leave your reference dangling: pointing to a space in memory that someday - like when someone important is running your code - may be filled with garbage without your reference knowing it. This be the way to madness, my friend.

This is exactly why smart pointers are a C++ programmer's best friend: once you understand what they're doing, you can all but ignore this sort of mess and just pass them around by value freely. Their lifecycle contract is very well defined, they clean up after themselves, they are exception safe. As long as you don't set up reference cycles - which is far less problematic in everyday usage than passing a dereferenced pointer by reference - or try to use auto_ptr in a standard container PLEASE READ THIS LINK AND UNDERSTAND IT, you've vastly reduced your memory problems.

Community
  • 1
  • 1
Matt
  • 10,434
  • 1
  • 36
  • 45
2

you need to use pointer in this case, the better way is to use smart pointer.

std::list<std::shared_ptr<vehicle> > lv;

In your list<vehicle> lv;, lv only contains vehicle type object, lv.insertEnd(*v1); will slice your object to vehicle type which is not allow as vehicle is abstract class.

billz
  • 44,644
  • 9
  • 83
  • 100
  • Thank you I'll try this.If I cannot do this that's not a big problem, I have this implemented with pointers to pointers and it's working, the only inconvenient is that I have to make resizes. – wormwood87 Jan 07 '13 at 02:00
1

since one cannot instantiate an object of abstract types, it failed to construct the object for insertion.

Also, the copy construction semantics of stl does not support polymorphic use. a "vehicle" list should only contain vehicle objects, not car objects.

You have to use container of pointers.