Reputation: 23
I have an interface, let's call it Creature
, who has virtual functions that cause it to be abstract.
I have child classes of this interface such as Dog
, Cat
, and Pig
.
The compiler doesn't seem to like the following line due to not being able to declare variable thing
to be of abstract type Creature
.
Creature thing = Dog();
I know I can't instantiate interfaces and the like, but this is just a Dog
being declared as a Creature
.
I need some way of having one declaration work for all the children (i.e., being able to put Dog()
, Cat()
, or Pig()
where Dog()
is in the line above).
Can this be done in c++ or am I misusing inheritance and interfaces completely?
Upvotes: 2
Views: 6845
Reputation: 2301
In C++ you have to realize the different between value and reference semantics, where-as in interpretet languages you tend to just deal with reference semantics (except for some odd cases with plain old data objects which have value semantics but besides the point).
In C++ all objects are values, e.g an object can never be null
, this has the implication that declaration specifies the storage requirement.
Consider the following
struct creature {
};
struct dog : public creature {
float cuteness;
};
The storage requirement for a dog is different than that of a creature, even if you allow the conversion this would result in slicing. For example, will fido bark or be silent? #include
class creature {
public:
virtual void speak() {
std::cout << "..." << std::endl;
}
};
class dog : public creature {
public:
virtual void speak() {
std::cout << "woof!" << std::endl;
}
};
int main(int argc, const char *argv[]) {
creature fido;
fido = dog();
fido.speak();
return 0;
}
However if you were to simply have a pointer or reference to the object it is a different matter. By pointer.
creature* fido = new dog();
fido->speak();
delete fido;
By reference.
dog fido;
creature& c = fido;
c.speak();
Beyond the scope of this question, but optionally a smart pointer.
std::unique_ptr<creature> fido(new dog);
Upvotes: 1
Reputation: 110648
Object types themselves are not polymorphic in C++. The line you've given declares a Creature
object and then attempts to initialise it with a Dog
object. If Creature
weren't abstract, this would result in slicing - thing
wouldn't be a Dog
any more, it would just be a Creature
. Since it is abstract, you simply can't have a Creature
object anyway.
You need to use pointers or references for polymorphic behaviour. Consider for example:
Creature* thing = new Dog();
You can now dereference thing
and use it as a Creature
, even though it's dynamic type is Dog
. However, using raw pointers like this is usually not recommended, as you have to manually ensure that the object is delete
d at some point. The ownership can become confusing. Your best bet is to put it in a smart pointer, such as:
std::unique_ptr<Creature> thing(new Dog()); // or std::make_unique when we have it
Here, I've demonstrated std::unique_ptr
, but the choice of smart pointer will depend on the ownership semantics for that object. A common alternative is std::shared_ptr
.
To demonstrate polymorphism with references:
Dog dog;
Creature& thing = dog;
// Can now use dog as a Creature
Upvotes: 9