借助 C/C++ 的union,可以设计出近似弱类型的变量,同一类型的变量可以承载不同类型的数据。比如说一个对象A,可以按如下不同的类型使用:
A a = 1;
A b = 1.1;
A c = "abc";
A d = true;
使用的时候可以按照其真实的类型来使用。比如字符串c以调用c.size()获得其长度。
这个想法来源于两个开源库的基础数据类型设计,一个是xmlrpclib库中XmlRpcValue设计,一个是xpdf中Object设计,非常的巧妙。核心在于定义一个union承载实际的数据,定义一个enum来标识数据实际的类型。
XmlRpcValue的数据承载部分设计为:
union { bool asBool; int asInt; double asDouble; struct tm* asTime; std::string* asString; BinaryData* asBinary; ValueArray* asArray; ValueStruct* asStruct; } _value; |
enum Type { TypeInvalid, TypeBoolean, TypeInt, TypeDouble, TypeString, TypeDateTime, TypeBase64, TypeArray, TypeStruct }; |
在使用此类对象的时候,先设置该对象的类型,然后再根据实际的类型进行运算。其实质仍然是严格类型的。但是从使用者
的角度看来,却是弱类型的。
此类对象的使用会对效率和空间有一定的影响。但影响都不大。
时间方面的影响主要在于很多时候需要进行类型判定,若类型不匹配,则无法完成运算。值得注意的是,很多类型匹配可以
在编译期间完成。比如,XmpRpcValue a = 1; XmlRpcValue b = true;空间方面主要是union分配空间是以最大的成员进行分配,但是如果大量使用指针,空间的多余耗费则不会很大。
xmlrpclib库中XmlRpcValue核心代码如下(已删除部分不相关代码)
class XmlRpcValue { // Non-primitive types
XmlRpcValue(std::string const& value) : _type(TypeString) XmlRpcValue(const char* value) : _type(TypeString) XmlRpcValue(struct tm* value) : _type(TypeDateTime)
//! Construct from xml, beginning at *offset chars into the string, updates offset //! Copy //! Destructor (make virtual if you want to subclass) //! Erase the current value // Operators bool operator==(XmlRpcValue const& other) const; operator bool&() { assertTypeOrInvalid(TypeBoolean); return _value.asBool; } XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); } XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; } } // Accessors |