【问题标题】:Passing objects that are subclasses of abstract X, and instantiating fields which are of type subclass of abstract X传递抽象 X 的子类的对象,并实例化抽象 X 的子类类型的字段
【发布时间】:2020-04-22 01:27:30
【问题描述】:

我有这个基类

struct Expr
{
    virtual void accept(std::shared_ptr<const Expr> &expr, ExprVisitor &visitor) = 0;

    explicit Expr() = default;
    virtual ~Expr() = default;
};

还有一些子类,例如:

struct Binary : Expr
{
    explicit Binary(Expr &left, Token &_operator, Expr &right);
    Expr left;
    Token _operator;
    Expr right;

    void accept(Expr &expr, ExprVisitor &visitor) override;
};

struct Grouping : Expr
{
    explicit Grouping(Expr &expression);
    Expr expression;

    void accept(Expr &expr, ExprVisitor &visitor) override;
};

现在由于 Expr 有一个纯虚函数,所以不可能有一个 Expr 对象,但我希望作为二进制和分组构造函数的参数,让它们采用其他二进制/分组/子类表达式。我该怎么做?

有没有办法将“X 的任何子类”作为参数传递,我实际上从不希望 X 成为可传递的参数(实际上不可能这样做,因为它是一个抽象类)

我一直在考虑使用智能指针,谁能举个例子?


编辑

所以我尝试实现智能指针,但我无法让我的其他类与智能指针交互:

// expr_impl.hpp
struct Binary : Expr
{
    explicit Binary(std::shared_ptr<const Expr> &left, Token &_operator, std::shared_ptr<const Expr> &right);
    std::shared_ptr<const Expr> left;
    Token _operator;
    std::shared_ptr<const Expr> right;

    void accept(std::shared_ptr<const Expr> &expr, ExprVisitor &visitor) override;
};

struct Grouping : Expr
{
    explicit Grouping(std::shared_ptr<const Expr> &expression);
    std::shared_ptr<const Expr> expression;

    void accept(std::shared_ptr<const Expr> &expr, ExprVisitor &visitor) override;
};

struct LiteralExpr : Expr
{
    explicit LiteralExpr(Literal &literal);
    const Literal literal;

    void accept(std::shared_ptr<const Expr> &expr, ExprVisitor &visitor);

};

// expr_impl.cpp

Binary::Binary(std::shared_ptr<const Expr> &left, Token &_operator, std::shared_ptr<const Expr> &right) : left(left), _operator(_operator), right(right) {}

void Binary::accept(std::shared_ptr<const Expr> &expr, ExprVisitor &visitor)
{
    visitor.visit(*this);
}

Grouping::Grouping(std::shared_ptr<const Expr> &expression) : expression(expression) {}

void Grouping::accept(std::shared_ptr<const Expr> &expr, ExprVisitor &visitor)
{
    visitor.visit(*this);
}

LiteralExpr::LiteralExpr(Literal &literal) : literal(literal) {}

void LiteralExpr::accept(std::shared_ptr<const Expr> &expr, ExprVisitor &visitor)
{
    visitor.visit(*this);
}

// exprvisitor.hpp

struct ExprVisitor
{

    virtual void visit(Binary &expr) = 0;
    virtual void visit(Grouping &expr) = 0;
    virtual void visit(LiteralExpr &expr) = 0;
    virtual void visit(Unary &expr) = 0;


    explicit ExprVisitor() = default;
    virtual ~ExprVisitor() = default;
};

// astprinter.hpp

struct AstPrinter : ExprVisitor
{

    void visit(Binary &expr) override;
    void visit(Grouping &expr) override;
    void visit(LiteralExpr &expr) override;
    void visit(Unary &expr) override;

    std::string result;
    std::string getResult();
};


// astprinter.cpp
void AstPrinter::visit(Binary &expr)
{
    result += "(";
    result += expr._operator.lexeme;
    expr.accept(expr.left, *this);
    // expr.accept(expr.right, *this);
    result += ")";
}

void AstPrinter::visit(Grouping &expr)
{
}

void AstPrinter::visit(LiteralExpr &expr)
{
}

【问题讨论】:

    标签: c++ pointers inheritance


    【解决方案1】:

    您可以使用智能指针来利用动态多态性。首先修改构造函数以接受指向基类的智能指针,并移除抽象类型的变量:

    #include<memory>
    
    struct Binary : Expr
    {
        //modify constructor to accept shared_ptrs
        Binary(std::shared_ptr<Expr> left, Token &_operator, std::shared_ptr<Expr> right);
        //class members includes shared_ptrs to base class
        std::shared_ptr<Expr> left;
        Token _operator;
        std::shared_ptr<Expr> right;
    
        //overriding functions MUST have the same argument list as the virtual function it overrides
        void accept(std::shared_ptr<const Expr> &expr, ExprVisitor &visitor) override;
    };
    
    struct Grouping : Expr
    {
        //modify constructor to accept shared_ptr to base class
        explicit Grouping(std::shared_ptr<Expr> expression);
        //class member includes shared_ptr to base class
        std::shared_ptr<Expr> expression;
    
        //overriding functions MUST have the same argument list as the virtual function it overrides
        void accept(std::shared_ptr<const Expr> &expr, ExprVisitor &visitor) override;
    };
    

    要使用,您必须使用 std::make_shared 将所有 Grouping 和 Binary 实例化动态分配到 shared_ptrs 中,并向上转换为 shared_ptrs-to-base:

    //struct for example below
    struct Unary : public Expr{
        Unary(Token _operator);
    
        Token operator;
    
        void accept(std::shared_ptr<const Expr> &expr, ExprVisitor &visitor) override;
    };
    
    Token incrementToken{"++"};
    //Construct shared_ptr to Unary (on the right hand side), then up-cast to shared_ptr to Expr (on the left hand side)
    std::shared_ptr<Expr> incrementExpression = std::make_shared<Unary>(incrementToken);
    
    //Construct shared_ptr to Grouping (on the right hand side) using incrementExpression, then up-cast to shared_ptr to Expr (on the left hand side)
    std::shared_ptr<Expr> exampleGrouping = std::make_shared<Grouping>(incrementExpression);
    
    Token addToken{"+"};
    //Construct shared_ptr to Binary (on the right hand side) using both incrementExpression and exampleGrouping, then up-cast to shared_ptr to Expr (on the left hand side)
    std::shared_ptr<Expr> addExpression = std::make_shared<Binary>(incrementExpression, addToken, exampleGrouping);
    

    通过这种方式,您永远不会实例化 Expr 类型的变量,而您不能,因为它是抽象的。但是,Binary 和 Grouping 的实例化的行为就好像它们是 Expr,因此可以不加选择地传递给 Binary 和 Grouping 的构造函数。

    通过使用智能指针,您可以避免直接处理内存管理。

    【讨论】:

    • 感谢您的回答。我已经尝试实现共享指针,但我无法让我的访问者函数通过指针与我的 Expr 子类进行交互。我觉得我在选角上做错了什么。你能检查一下我的代码 sn-ps 看看我做错了什么吗?我认为问题在于我的访客职能
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-07
    • 1970-01-01
    相关资源
    最近更新 更多