微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

转换为没有 unique_ptr 的派生类

如何解决转换为没有 unique_ptr 的派生类

背景

我正在使用 Bison 和 Flex 创建一个 Cpp 解析器,但我偶然发现了一个问题:在我的解析器中,我需要一个基类对象的向量,比如 shapes。根据对象具有的派生类,我需要访问不同的成员。因此,我的意图是将 unique_ptr 存储在向量中。然后在访问时,我可以将它们动态转换为它们的派生类型。

问题

但是,我无法让 Bison 正确处理 unique_ptrs。无论我如何指定 parser.yy 文件,在编译时我都会遇到像

这样的错误

usr/include/c++/9/bits/stl_uninitialized.h:127:72: 错误:静态断言失败:结果类型必须可从输入范围的值类型构造

根据 this post Bison 不能很好地处理 unique_ptrs(据我了解 Bison 在内部没有使用 std::move()),我认为情况仍然如此.

我的问题

因为我希望保持类层次结构不变并且不想修复 Bison 本身的错误从基类转换到派生类时是否有使用 unique_ptrs 的替代方法

代码示例

特别是,我希望在不使用 unique_ptrs 的情况下执行以下操作。

enum Shape_type{
    SHAPE_TYPE_CIRCLE,SHAPE_TYPE_TRIANGLE,};

class Shape{
public:
    enum Shape_type type;
    Shape(enum Shape_type type){ this->type=type; }
    virtual ~Shape(){}
};

class Circle: public Shape{
    int r;
public:
    int get_r(){ return this->r; }
    Circle(int r):Shape(SHAPE_TYPE_CIRCLE){ this->r=r; }
};

int main(void){
    std::vector<std::unique_ptr<Shape>> shapes;
    std::unique_ptr<Shape> circle_ptr = std::make_unique<Circle>(42);
    shapes.push_back(std::move(circle_ptr));
    
    for(auto& s_ptr: shapes){
        switch(s_ptr->type){
        case SHAPE_TYPE_CIRCLE:
        {
            auto c = dynamic_cast<Circle&>(*s_ptr);
            std::cout << "circle with r=" << c.get_r() << std::endl;
            break;
        }
        default: {
            std::cout << "other shape" << std::endl;
            break;
        }
        }
    }
    
    return 0;
}

非常感谢任何帮助。提前致谢。

解决方法

多态方式是(用 std::unique_ptr 替换不可复制的 std::shared_ptr):

class Shape{
public:
    virtual ~Shape() = default;
    virtual void draw() const = 0;
};

class Circle: public Shape
{
    int r;
public:
    explicit Circle(int r): r(r) {}
    int get_r() const { return r; }

    void draw() const override { std::cout << "circle with r=" << r << std::endl; }
};

class Square: public Shape
{
    int side;
public:
    explicit Square(int side): side(side) {}
    int get_side() const { return side; }

    void draw() const override { std::cout << "square with side=" << side << std::endl; }
};

int main()
{
    std::vector<std::shared_ptr<Shape>> shapes { std::make_shared<Circle>(42) };
    
    for (const auto& shape_ptr: shapes)
    {
        shape_ptr->draw();
    }
    return 0;
}

使用std::variant,您可能会

class Circle
{
    int r;
public:
    explicit Circle(int r): r(r) {}
    int get_r() const { return r; }

    void draw() const { std::cout << "circle with r=" << r << std::endl; }
};

class Square
{
    int side;
public:
    explicit Square(int side): side(side) {}
    int get_side() const { return side; }

    void draw() const { std::cout << "square with side=" << side << std::endl; }
};

using Shape = std::variant<Circle,Square>;

int main()
{
    std::vector<Shape> shapes { Circle(42) };
    
    for (const auto& shape: shapes)
    {
        std::visit([](const auto& shape){ shape.draw(); },shape);
    }
    return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。