c++ - 为什么智能指针 vector 不是指向实现与该接口(interface)协变的接口(interface)的项目?

标签 c++ covariance contravariance

为什么智能指针 vector 不与 item 实现的接口(interface)协变?例如如果我有一个指向狗的指针 vector ,为什么我不能将它用作指向 iAnimal 的指针 vector ?

#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 的 vector 中。

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(和其他类似的库结构)完全禁止这种转换以防止出现这样的错误。

关于c++ - 为什么智能指针 vector 不是指向实现与该接口(interface)协变的接口(interface)的项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51502834/

相关文章:

c# - 协方差和 IList

scala - 如何解决在逆变位置使用协变类型参数的问题

c++ - 指向对象的指针的未声明标识符 vector

c++ - 在循环范围之外声明参数是否更有效?

c++ - 将double转换为wstring,但wstring必须用科学计数法格式化

java - Java中的协方差和重载

c++ - C++ fmt::print 与 fmt::format_to 命名的技术背景?

C# 泛型接口(interface)协方差

c# - 委托(delegate)方差规则的怪异示例

java - 在 Java 中调用逆变方法