Why isn't a vector of smart pointers covariant with an interface that item implements? e.g. if I have a vector of pointers to a dog, why can't I use that as a vector of pointers to iAnimal?
#include <iostream>
#include <memory>
#include <string>
#include <vector>
struct iAnimal
{
virtual std::string speak() const = 0;
};
struct iMammal : public iAnimal
{
virtual std::string speak() const = 0;
virtual int legs() const = 0;
};
struct Dog : public iMammal
{
std::string speak() const
{
return "WOOF!";
}
int legs() const
{
return 4;
}
};
void giveMammals(std::vector<std::shared_ptr<iMammal>> an)
{
for (const auto x : an)
{
x->legs();
}
}
void giveAnimals(std::vector<std::shared_ptr<iAnimal>> an)
{
for (const auto x : an)
{
x->speak();
}
}
int main()
{
std::vector<std::shared_ptr<Dog>> vec1 = { std::make_shared<Dog>() };
std::vector<std::shared_ptr<iMammal>> vec= { std::make_shared<Dog>() };
giveAnimals(vec);
giveMammals(vec1);
return 0;
}
The reason is that the kind of code you're proposing could be easily exploited to do a lot of nasty things. For one example, let's see how, trivially, if this code were legal (it's not) it would be possible to insert a Cat
into a vector of Dog
's.
struct Cat : public iMammal {
std::string speak() const
{
return "meow.";
}
int legs() const
{
return 4;
}
};
void giveAnimals(std::vector<std::shared_ptr<iAnimal>> & an) {
//This, on its own, is perfectly legal given the type that `an` is.
an.emplace_back(std::make_shared<Cat>());
for (auto const& x : an)
{
x->speak();
}
}
int main() {
std::vector<std::shared_ptr<Dog>> vec = { std::make_shared<Dog>() };
giveAnimals(vec);//Uhhhh.......
for(auto const& dog_ptr : vec) {
dog_ptr->speak();//These are not all going to bark!
}
}
std::vector
(and other similar library constructs) prohibit this kind of conversion exactly to prevent mistakes/errors like this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With