用户登录  |  傲看软件园 用户注册
文章中心广告代码ASP源码PHP源码JSP源码.NET源码源码相关傲看留言板繁體中文
当前位置:傲看软件园文章中心编程开发编程语言

让C++的对象支持多类型

减小字体 增大字体 作者:佚名  来源:本站整理  发布时间:2009-01-16 10:54:18

借助 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))); }

bool operator==(XmlRpcValue const& other) const;
bool operator!=(XmlRpcValue const& other) const;

operator bool&() { assertTypeOrInvalid(TypeBoolean); return _value.asBool; }
operator int&() { assertTypeOrInvalid(TypeInt); return _value.asInt; }
operator double&() { assertTypeOrInvalid(TypeDouble); return _value.asDouble; }
operator std::string&() { assertTypeOrInvalid(TypeString); return *_value.asString; }
operator BinaryData&() { assertTypeOrInvalid(TypeBase64); return *_value.asBinary; }
operator struct tm&() { assertTypeOrInvalid(TypeDateTime); return *_value.asTime; }

XmlRpcValue const& operator[](int i) const { assertArray(i+1); return _value.asArray->at(i); }
XmlRpcValue& operator[](int i) { assertArray(i+1); return _value.asArray->at(i); }

XmlRpcValue& operator[](std::string const& k) { assertStruct(); return (*_value.asStruct)[k]; }
XmlRpcValue& operator[](const char* k) { assertStruct(); std::string s(k); return (*_value.asStruct)[s];

}

// Accessors
//! Return true if the value has been set to something.
bool valid() const { return _type != TypeInvalid; }  //! Return the type of the value stored. \see Type.
Type const &getType() const { return _type; }

//! Return the size for string, base64, array, and struct values.
int size() const;

//! Specify the size for array values. Array values will grow beyond this size if needed.
void setSize(int size) { assertArray(size); }

//! Check for the existence of a struct member by name.
bool hasMember(const std::string& name) const;

// Type tag and values
Type _type;

// At some point I will split off Arrays and Structs into
// separate ref-counted objects for more efficient copying.
union {
bool asBool;
int asInt;
double asDouble;
struct tm* asTime;
std::string* asString;
BinaryData* asBinary;
ValueArray* asArray;
ValueStruct* asStruct;
} _value;

};



xpdf中Object的核心代码如下



enum ObjType {
// simple objects
objBool, // boolean
objInt, // integer
objReal, // real
objString, // string
objName, // name
objNull, // null

// complex objects
objArray, // array
objDict, // dictionary
objStream, // stream
objRef, // indirect reference

// special objects
objCmd, // command name
objError, // error return from Lexer
objEOF, // end of file return from Lexer
objNone // uninitialized object
};

class Object {
public:

// Default constructor.
Object():
type(objNone) {}

// Initialize an object.
Object *initBool(GBool boolnA)
{ initObj(objBool); booln = boolnA; return this; }
Object *initInt(int intgA)
{ initObj(objInt); intg = intgA; return this; }
Object *initReal(double realA)
{ initObj(objReal); real = realA; return this; }
Object *initString(GString *stringA)
{ initObj(objString); string = stringA; return this; }
Object *initName(char *nameA)
{ initObj(objName); name = copyString(nameA); return this; }
Object *initNull()
{ initObj(objNull); return this; }
Object *initArray(XRef *xref);
Object *initDict(XRef *xref);
Object *initDict(Dict *dictA);
Object *initStream(Stream *streamA);
Object *initRef(int numA, int genA)
{ initObj(objRef); ref.num = numA; ref.gen = genA; return this; }
Object *initCmd(char *cmdA)
{ initObj(objCmd); cmd = copyString(cmdA); return this; }
Object *initError()
{ initObj(objError); return this; }
Object *initEOF()
{ initObj(objEOF); return this; }

// Copy an object.
Object *copy(Object *obj);

// If object is a Ref, fetch and return the referenced object.
// Otherwise, return a copy of the object.
Object *fetch(XRef *xref, Object *obj);

// Free object contents.
void free();

// Type checking.
ObjType getType() { return type; }
GBool isBool() { return type == objBool; }
GBool isInt() { return type == objInt; }
GBool isReal() { return type == objReal; }
GBool isNum() { return type == objInt || type == objReal; }
GBool isString() { return type == objString; }
GBool isName() { return type == objName; }
GBool isNull() { return type == objNull; }
GBool isArray() { return type == objArray; }
GBool isDict() { return type == objDict; }
GBool isStream() { return type == objStream; }
GBool isRef() { return type == objRef; }
GBool isCmd() { return type == objCmd; }
GBool isError() { return type == objError; }
GBool isEOF() { return type == objEOF; }
GBool isNone() { return type == objNone; }

// Special type checking.
GBool isName(char *nameA)
{ return type == objName && !strcmp(name, nameA); }
GBool isDict(char *dictType);
GBool isStream(char *dictType);
GBool isCmd(char *cmdA)
{ return type == objCmd && !strcmp(cmd, cmdA); }

// Accessors. NB: these assume object is of correct type.
GBool getBool() { return booln; }
int getInt() { return intg; }
double getReal() { return real; }
double getNum() { return type == objInt ? (double)intg : real; }
GString *getString() { return string; }
char *getName() { return name; }
Array *getArray() { return array; }
Dict *getDict() { return dict; }
Stream *getStream() { return stream; }
Ref getRef() { return ref; }
int getRefNum() { return ref.num; }
int getRefGen() { return ref.gen; }
char *getCmd() { return cmd; }

// Array accessors.
int arrayGetLength();
void arrayAdd(Object *elem);
Object *arrayGet(int i, Object *obj);
Object *arrayGetNF(int i, Object *obj);

// Dict accessors.
int dictGetLength();
void dictAdd(char *key, Object *val);
GBool dictIs(char *dictType);
Object *dictLookup(char *key, Object *obj);

  Object *dictLookupNF(char *key, Object *obj);
char *dictGetKey(int i);
Object *dictGetVal(int i, Object *obj);
Object *dictGetValNF(int i, Object *obj);

// Stream accessors.
GBool streamIs(char *dictType);
void streamReset();
void streamClose();
int streamGetChar();
int streamLookChar();
char *streamGetLine(char *buf, int size);
Guint streamGetPos();
void streamSetPos(Guint pos, int dir = 0);
Dict *streamGetDict();
private:

ObjType type; // object type
union { // value for each type:
GBool booln; // boolean
int intg; // integer
double real; // real
GString *string; // string
char *name; // name
Array *array; // array
Dict *dict; // dictionary
Stream *stream; // stream
Ref ref; // indirect reference
char *cmd; // command
};
};

Tags:

作者:佚名

文章评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论

精品栏目导航

关于本站 | 网站帮助 | 广告合作 | 下载声明 | 友情连接 | 网站地图
冀ICP备08004437号 | 客服Q:354766721 | 交流群83228313
傲看软件园 - 绿色软件,破解软件下载站! 源码网 源码之家 绿软之家
Copyright © 2003-2010 OkHan.Net. All Rights Reserved .
页面执行时间:265.62500 毫秒
Powered by:OkHan CMS Version 4.0.0 SP2