Почему вектор интеллектуальных указателей не ковариантен с интерфейсом, который реализует элемент? например если у меня есть вектор указателей на собаку, почему я не могу использовать его как вектор указателей на 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;
}
Причина в том, что предлагаемый вами код может быть легко использован для совершения множества неприятных вещей. Для одного примера, давайте посмотрим, как, тривиально, если бы этот код был законным (это не так), было бы возможно вставить Cat
в вектор 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
(и другие подобные библиотечные конструкции) запрещают этот вид преобразования именно для того, чтобы предотвратить подобные ошибки.
Других решений пока нет …