gpt4 book ai didi

表达式计算的 C++ 设计问题

转载 作者:太空狗 更新时间:2023-10-29 23:04:10 32 4
gpt4 key购买 nike

我需要创建类来表示表达式,例如 someVar=2*(5+3)^5。为此,我想要以下类(class):

class IExpression
{
public:
virtual ~IExpression( void ) { }
virtual CValue eval( const CScope & ) const = 0;
};

class CConstant : public IExpression
{
protected:
const CValue _value;
public:
virtual CValue eval( const CScope & ) const { return this->_value; }
};

class COperation : public IExpression
{
protected:
const IExpression * const _left;
const operator_e _eOper;
const IExpression * const _right;
public:
virtual ~COperation( void );
virtual CValue eval( const CScope & ) const;
};

class CVariable : public IExpression
{
protected:
const string _name;
public:
virtual CValue eval( const CScope & scope ) const { return scope.access( this->_name ); }
};

同时假设我有一个 CScope 类,CVariable::eval() 使用它来访问变量:

class CScope
{
protected:
map<string, CValue> _mVars;
public:
inline const CValue & access( const string & name ) const;
inline CValue & access( const string & name );
};

我这里有个问题。想象一下,我有一个使用运算符的操作,需要通过引用访问值,以便可以设置它,如 =+=。对于我会做的作业:

CValue COperation::eval( const CScope & scope ) const
{
switch( this->_eOper )
{
// ...
case E_ASSIGN:
return this->_left->eval( scope ) = this->right->eval( scope );
}
}

这里的问题是 this->_left->eval(scope),其中 _left 指向一个 CVariable,正在运行返回由该变量的名称标识的 CValue 的拷贝,并且赋值不会起作用。

我可以更改方法 eval() 的签名以使其返回 CValue &,但这会导致问题,因为在 COperation 的情况下,操作的结果是COperation::eval() 返回后立即销毁的临时变量。

你知道我该怎么做吗?

最佳答案

来自对 OP 的评论中的讨论:

42 = 2 应该发生什么?

Well CConstant::eval() would return a temporary copy of the member CValue which would be assigned, but that would not do anything since it would be a temporary value and not the member itself that would get assigned. It would be like doing : 3 + 5 = 10;

我不是特别喜欢这种设计,因为它允许容易出错或无意义的表达式,但让我们尝试实现它:

class IExpression
{
public:
virtual ~IExpression( void ) { }
virtual CValue& eval( CScope & ) const = 0;
};

通过这个接口(interface),我们可以改变表达式的任何返回值。当然,它需要使用临时对象。您可以将它们推送到 CScope 中的堆栈,这需要修改范围对象。例如:

class CConstant : public IExpression
{
protected:
const CValue _value;
public:
virtual CValue& eval( CScope & scope ) const
{
return scope.push(_value);
}
};

变量保持大致相同:

class CVariable : public IExpression
{
protected:
const string _name;
public:
virtual CValue& eval( CScope & scope ) const
{ return scope.access( this->_name ); }
};

然后,作业就按照您编写的方式工作:

CValue COperation::eval( CScope & scope ) const
{
switch( this->_eOper )
{
// ...
case E_ASSIGN:
return this->_left->eval( scope ) = this->right->eval( scope );
}
}

如果您不想始终创建值的拷贝,则可以限制在赋值的 LHS 中使用常量时复制常量。

class IExpression
{
public:
virtual ~IExpression( void ) { }
virtual CValue rvalue( CScope const& ) const = 0;
virtual CValue& lvalue( CScope & ) const = 0;
};

class CConstant : public IExpression
{
protected:
const CValue _value;
public:
virtual CValue& lvalue( CScope & scope ) const
{
return scope.push(_value);
}
virtual CValue rvalue( CScope const& scope ) const
{
return _value;
}
};

CValue COperation::eval( CScope & scope ) const
{
switch( this->_eOper )
{
// ...
case E_ASSIGN:
return this->_left->lvalue( scope ) = this->right->rvalue( scope );
}
}

我们还可以在本地创建临时文件:

class CMutableValue
{
private:
union { CValue _cpy; };
bool _tmp;
public:
CValue& _ref;

CMutableValue(CValue & var)
: _tmp(false), _ref(var) {}
CMutableValue(CValue const & val)
: _cpy(val), _tmp(true), _ref(_cpy) {}
CMutableValue(CMutableValue const& source)
: _tmp(source._tmp), _ref( source._tmp ? _cpy : source._ref )
{
if(source._tmp) new( (void*)&_cpy ) CValue(source._ref);
}

// delete in C++11, or private in C++03
CMutableValue& operator=(CMutableValue const&) = delete;
};

这试图避免临时对象的一些生命周期问题,但我认为它仍然很危险。

class IExpression
{
public:
virtual ~IExpression( void ) { }
virtual CMutableValue eval( CScope const& ) const = 0;
};

class CConstant : public IExpression
{
protected:
const CValue _value;
public:
virtual CValue& eval( CScope & scope ) const
{
return CMutableValue(_value);
}
};

CValue COperation::eval( CScope & scope ) const
{
switch( this->_eOper )
{
// ...
case E_ASSIGN:
return this->_left->eval( scope )._ref
= this->right->eval( scope )._ref;
}
}

关于表达式计算的 C++ 设计问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23540578/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com