0

I'm learning C++ by myself, "creating" a RPG. However, I'm stuck at point of creating a class named Item, which would be the base class for all game items (or if it was in Java, an interface). Here's my code:

class Item {

    public:

    virtual const char* GetName() = 0;
};

I read something about "pure virtual" functions, which I'm using.

My Character class, where I use my Item:

class Character {

  // some code...

  void ConsumeItem(Item item);

}

But gcc gives me this error:

g++ -Wall -o adventure character.cpp adventure.cpp
In file included from adventure.cpp:3:0:
character.h:36:24: error: cannot declare parameter ‘item’ to be of abstract type ‘Item’
item.h:4:7: note:   because the following virtual functions are pure within ‘Item’:
item.h:11:22: note:     virtual const char* Item::GetName()

I'm very new to OOP in C++, as it is very different from Java. I already read some articles about abstract classes in C++, but I just can't get it working.

Can you please tell me the right way to achieve this?

AusCBloke
  • 18,014
  • 6
  • 40
  • 44
André
  • 323
  • 4
  • 18
  • 6
    You need to learn basic C++ constructs first, like references and pointers. I hope this won't kill your buzz, but you can't count with what you know from Java in C++. The languages are quite different. I'll recommend [a good introductory C++ book](http://stackoverflow.com/q/388242/46642). – R. Martinho Fernandes Jan 02 '12 at 23:50
  • Do not start learning C++ by writing an RPG. Try Pong or Conway's Game of Life (if you want to stick to games) and learn the basic concepts first. Today it may sound disappointing, but one day you will give me a +1 for this. – Alexander Gessler Jan 02 '12 at 23:56
  • The term is "type splicing" essentially you're creating an instance of item based on possible a derived type - the compiler complains that the type can't be instantiated because it has pure virtual methods. – Jared Krumsie Jan 03 '12 at 00:48
  • In fact, I already know C, but since there is no OOP paradigm, I moved to C++. That's why I'm trying to create this RPG (just a couple of classes, to see OOP in action). However, I will try to read something more about C++, to get a better background from the language. Thanks for the tips! – André Jan 03 '12 at 09:36

6 Answers6

3

In Java, doing something like that will create a reference to an Item, which you can then assign an instance of a concrete subclass.

However in C++, Item item will create an instance of Item, which isn't allowed since Item contains a pure virtual function.

To avoid this problem, you need to make item a pointer or a reference, like:

void ConsumeItem(Item *item);
AusCBloke
  • 18,014
  • 6
  • 40
  • 44
  • For the OP's benefit, this is referred to as polymorphism, i.e. `item` is a polymorphic pointer. – Chris Parton Jan 03 '12 at 03:11
  • It's really a big difference. But after your explanation, I see the things more clear, and it makes sense after all. Thanks to everyone! – André Jan 03 '12 at 09:32
2

Typically, if you have a class hierarchy you want to use references or [smart] pointers to your objects. In you code excerpts, Item is an abstract base class and thus can't be created. However, the Item parameter to your ConsumeItem function is passed by value: without a "&" and a "*" the objects are values in C++. You probably want to pass the parameter using one of those:

  • void ConsumeItem(Item& item) // pass by reference
  • void ConsumeItem(Item const& item) // pass non-modifiable object by reference
  • void ConsumeItem(Item* item) // pass using a pointer
  • void ConsumeItem(std::shared_ptr<Item> item) // pass using a smart pointer

BTW, something you'd not easily come about is: if your base class has any virtual function, make you destructor virtual, too! Otherwise you'll almost certainly running into undefined behavior which is typically a Bad Thing. That is, in your Item class add:

virtual ~Item() {} // can also be defined out of line but always has to be defined
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
0

Since Item is an abstract class, you can't use an instance of it, you should use either a pointer * or a reference & to it.

In your case, you are passing an instance of it, you should pass a pointer instead:

class Character {

  // some code...

  void ConsumeItem(Item* item);

}

Thus, you are actually passing a pointer to an object of a class which is NOT abstract and inherited from Item.

Tamer Shlash
  • 9,314
  • 5
  • 44
  • 82
0

Make ConsumeAccept receive a reference (or a pointer) to an Item:

void ConsumeItem(Item& item);

Item is polymorphic and its exact size depends on the deriving class that implements it, therefore it is not allowed to pass it by value (it would theoretically be possible if it didn't have a pure virtual function, but the effect would not be the intended).

Make sure you understand what pointers, references and value types are in C++. In Java, all objects are treated as references with no extra sign (such as &) to denote this. The difference is crucial.

Alexander Gessler
  • 45,603
  • 7
  • 82
  • 122
0

You cannot instantiate classes that contain pure virtual methods, and Item item would be such un instance. You can create pointers to them, though, so Item *item will work.

Ricardo Cárdenes
  • 9,004
  • 1
  • 21
  • 34
0

In order to use polymorphism in C++ you need to use pointers (or references, but I am going to ignore that for now).

You have to store your polymorphic objects as pointers, pass them as pointers, etc.

A modified ConsumeItem would be:

class Character {

  // some code...

  void ConsumeItem(Item* item);

}

This would be further improved by using shared_ptr's to avoid memory leaks.

class Character {

  // some code...

  void ConsumeItem(std::shared_ptr<Item> item);

}

Passing everything as shared_ptr's would actually very closely approximate Java semantics(watch out for cycles though).