让C++的对象支持多类型
来源:优易学  2011-12-26 16:39:09   【优易学:中国教育考试门户网】   资料下载   IT书店

  借助 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 {
  public:
  enum Type {
  TypeInvalid,
  TypeBoolean,
  TypeInt,
  TypeDouble,
  TypeString,
  TypeDateTime,
  TypeBase64,
  TypeArray,
  TypeStruct
  };
  // Non-primitive types
  typedef std::vector<char> BinaryData;
  typedef std::vector<XmlRpcValue> ValueArray;
  typedef std::map<std::string, XmlRpcValue> ValueStruct;
  //! Constructors
  XmlRpcValue() : _type(TypeInvalid) { _value.asBinary = 0; }
  XmlRpcValue(bool value) : _type(TypeBoolean) { _value.asBool = value; }
  XmlRpcValue(int value) : _type(TypeInt) { _value.asInt = value; }
  XmlRpcValue(double value) : _type(TypeDouble) { _value.asDouble = value; }
  XmlRpcValue(std::string const& value) : _type(TypeString)
  { _value.asString = new std::string(value); }
  XmlRpcValue(const char* value) : _type(TypeString)
  { _value.asString = new std::string(value); }
  XmlRpcValue(struct tm* value) : _type(TypeDateTime)
  { _value.asTime = new struct tm(*value); }
  XmlRpcValue(void* value, int nBytes) : _type(TypeBase64)
  {
  _value.asBinary = new BinaryData((char*)value, ((char*)value)+nBytes);
  }
  //! Construct from xml, beginning at *offset chars into the string, updates offset
  XmlRpcValue(std::string const& xml, int* offset) : _type(TypeInvalid)
  { if ( ! fromXml(xml,offset)) _type = TypeInvalid; }
  //! Copy
  XmlRpcValue(XmlRpcValue const& rhs) : _type(TypeInvalid) { *this = rhs; }
  //! Destructor (make virtual if you want to subclass)
  /*virtual*/ ~XmlRpcValue() { invalidate(); }
  //! Erase the current value
  void clear() { invalidate(); }
  // Operators
  XmlRpcValue& operator=(XmlRpcValue const& rhs);
  XmlRpcValue& operator=(int const& rhs) { return operator=(XmlRpcValue(rhs)); }
  XmlRpcValue& operator=(double const& rhs) { return operator=(XmlRpcValue(rhs)); }
  XmlRpcValue& operator=(const char* rhs) { return operator=(XmlRpcValue(std::string(rhs))); }

[1] [2] [3] 下一页

责任编辑:小草

文章搜索:
 相关文章
热点资讯
资讯快报
热门课程培训