我正在用C++编写一个解释器,用于我简洁设计的类似lisp的语言.这是为了娱乐和学习,所以我不会追求绝对的效率.但我想尝试一个非常干净的C++代码.我目前想知道如何实现内置函数.
基本上,我做的是这样的:
我有一个抽象基类DataObject,它只提供类型信息(目前是double,int,bool),并由特定的数据容器继承,如:
class DataObject
{
public:
virtual const Type *type() = 0;
};
template<class T, const Type * myType>
class DataObjectValue : public DataObject
{
T value;
public:
const Type *type(){return myType;}
};
Run Code Online (Sandbox Code Playgroud)
但是,当我想要表演时,我必须做以下事情:
DataObject * sum(DataObject *a, DataObject *b)
{
if(a->type() == &Integer and b->type == &Integer)
{
DataObjectValue<int>* ia = dynamic_cast< DataObjectValue<int>* >(a);
DataObjectValue<int>* ib = dynamic_cast< DataObjectValue<int>* >(b);
return new DataObjectValue<int>(ia->value+ib->value);
}
else if(a->type() == &Real and b->type == &Real)
{
DataObjectValue<double>* ra = dynamic_cast< DataObjectValue<double>* >(a);
DataObjectValue<double>* rb = dynamic_cast< DataObjectValue<double>* >(b);
return new DataObjectValue<double>(ra->value+rb->value);
}
else...
}
Run Code Online (Sandbox Code Playgroud)
这很快就会很烦人(对于 - */<< => = <> ....)以及其他几种类型.这很难维护.当然,通过在各处引入大量模板,我已经简化了尽可能多的过程,但是,我仍然不禁想到必须有一种更清洁的方式.你是a)看看我的问题是什么(我怀疑我的解释,而不是你的能力)b)有什么建议吗?
您当前的实现基本上以正在存储的确切类型执行类型擦除,并且您以一种稍微不寻常的方式执行此操作(为什么不使用枚举而不是指向唯一对象的指针?)
我首先向基类提供促销操作,并在每个级别中实施它们:
enum DataType {
type_bool,
type_int,
type_double
};
struct DataObject {
virtual ~DataObject() {} // remember to provide a virtual destructor if you
// intend on deleting through base pointers!!!
virtual DataType type() const = 0;
virtual bool asBool() const = 0;
virtual int asInt() const = 0;
virtual double asDouble() const = 0;
};
Run Code Online (Sandbox Code Playgroud)
然后你可以在一个简单的函子中实现这些操作:
template <typename T>
T sum_impl( T lhs, T rhs ) {
return lhs + rhs;
}
Run Code Online (Sandbox Code Playgroud)
并提供一个简单的调度函数:
DataType promoteTypes( DataType lhs, DataType rhs ) {
if ( lhs == type_double || rhs == type_double ) {
return type_double;
} else if ( lhs == type_int || rhs == type_int ) {
return type_int;
} else {
return type_bool;
}
}
template <template <typename T> T operation (T,T)>
DataObject* perform_operation( DataObject* lhs, DataObject* rhs, operation op ) const {
DataType result_type = promoteTypes( lhs->type(), rhs->type() );
switch ( result_type ) {
case type_double:
return new DataObjectValue<double>( op( lhs->asDouble(), rhs->asDouble() );
case type_int:
return new DataObjectValue<int>( op( lhs->asInt(), rhs->asInt() );
case type_bool:
return new DataObjectValue<bool>( op( lhs->asBool(), rhs->asBool() );
default:
abort();
}
}
Run Code Online (Sandbox Code Playgroud)
所有的部分都就位后,您可以几乎简单地实现操作,只需为特定操作提供一个函数模板(如上所述sum),然后使用其余的地方:
// sum_impl as above
DataObject* sum( DataObject* lhs, DataObject* rhs ) {
return perform_operation( lhs, rhs, sum_impl );
}
Run Code Online (Sandbox Code Playgroud)
现在这只是我要使用的模式,但我会做一些更改,我更喜欢使用尽可能少的指针,这意味着我不会通过指针传递参数,而是通过引用传递参数。另外,我会进行适当的类型擦除(看看 boost any)并创建Object一个包含元素的完整类型DataObject,然后对该类型(而不是层次结构)执行操作。这将使您能够提供也按值返回的函数(并在内部隐藏动态内存分配,这也意味着资源管理可以在内部控制,Object而不是用户代码的责任)。通过这些更改,您可以重用和简化上述结构并提供更清晰的解决方案。
| 归档时间: |
|
| 查看次数: |
409 次 |
| 最近记录: |